summaryrefslogtreecommitdiff
path: root/libddekit
diff options
context:
space:
mode:
Diffstat (limited to 'libddekit')
-rw-r--r--libddekit/Makefile53
-rw-r--r--libddekit/condvar.c52
-rw-r--r--libddekit/config.h13
-rw-r--r--libddekit/dde.h14
-rw-r--r--libddekit/ddekit/assert.h23
-rw-r--r--libddekit/ddekit/condvar.h53
-rw-r--r--libddekit/ddekit/debug.h8
-rw-r--r--libddekit/ddekit/initcall.h42
-rw-r--r--libddekit/ddekit/inline.h2
-rw-r--r--libddekit/ddekit/interrupt.h57
-rw-r--r--libddekit/ddekit/lock.h83
-rw-r--r--libddekit/ddekit/memory.h144
-rw-r--r--libddekit/ddekit/panic.h16
-rw-r--r--libddekit/ddekit/pci.h199
-rw-r--r--libddekit/ddekit/pgtab.h86
-rw-r--r--libddekit/ddekit/printf.h35
-rw-r--r--libddekit/ddekit/resources.h14
-rw-r--r--libddekit/ddekit/semaphore.h50
-rw-r--r--libddekit/ddekit/thread.h145
-rw-r--r--libddekit/ddekit/timer.h59
-rw-r--r--libddekit/ddekit/types.h22
-rw-r--r--libddekit/init.c31
-rw-r--r--libddekit/initcall.c27
-rw-r--r--libddekit/interrupt.c288
-rw-r--r--libddekit/list.c74
-rw-r--r--libddekit/list.h42
-rw-r--r--libddekit/lock.c55
-rw-r--r--libddekit/malloc.c49
-rw-r--r--libddekit/memory.c278
-rw-r--r--libddekit/panic.c28
-rw-r--r--libddekit/pci.c405
-rw-r--r--libddekit/pgtab.c213
-rw-r--r--libddekit/printf.c107
-rw-r--r--libddekit/resources.c125
-rw-r--r--libddekit/thread.c434
-rw-r--r--libddekit/timer.c342
-rw-r--r--libddekit/util.h8
-rw-r--r--libddekit/vm_param.h7
38 files changed, 3683 insertions, 0 deletions
diff --git a/libddekit/Makefile b/libddekit/Makefile
new file mode 100644
index 00000000..59f75095
--- /dev/null
+++ b/libddekit/Makefile
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2009 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := libddekit
+makemode := library
+
+libname = libddekit
+SRCS= condvar.c init.c interrupt.c lock.c malloc.c memory.c \
+ pci.c pgtab.c printf.c resources.c list.c panic.c \
+ thread.c timer.c initcall.c
+installhdrs = ddekit/condvar.h ddekit/lock.h \
+ ddekit/semaphore.h ddekit/debug.h \
+ ddekit/inline.h ddekit/panic.h \
+ ddekit/thread.h ddekit/types.h \
+ ddekit/pgtab.h ddekit/printf.h \
+ ddekit/pci.h ddekit/assert.h \
+ ddekit/interrupt.h ddekit/resources.h \
+ ddekit/memory.h ddekit/timer.h \
+ ddekit/initcall.h
+
+installhdrsubdir = .
+LCLHDRS = $(installhdrs) \
+ dde.h \
+ config.h list.h util.h
+
+MIGSTUBS = experimentalUser.o
+OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS))
+
+HURDLIBS = ports shouldbeinlibc hurd-slab
+OTHERLIBS = -lpthread
+
+MIGCOMSFLAGS = -prefix dde_
+
+include ../Makeconf
+
+LIBS += -lpciaccess
+
+$(libname).so.$(hurd-version):
+ echo "INPUT ( $(libname).a )" > $@
diff --git a/libddekit/condvar.c b/libddekit/condvar.c
new file mode 100644
index 00000000..64df3ed6
--- /dev/null
+++ b/libddekit/condvar.c
@@ -0,0 +1,52 @@
+/**
+ * Unchecked (no BSD invariants) condition variable implementation for
+ * dde-internal use. Written from scratch.
+ *
+ * \author Thomas Friebel <tf13@os.inf.tu-dresden.de>
+ */
+#include <pthread.h>
+
+#include "ddekit/memory.h"
+#include "ddekit/condvar.h"
+
+struct ddekit_condvar {
+ pthread_cond_t cond;
+};
+
+ddekit_condvar_t *ddekit_condvar_init() {
+ ddekit_condvar_t *cvp;
+
+ cvp = ddekit_simple_malloc (sizeof (*cvp));
+
+ if (cvp == NULL)
+ return NULL;
+
+ pthread_cond_init (&cvp->cond, NULL);
+ return cvp;
+}
+
+void ddekit_condvar_deinit(ddekit_condvar_t *cvp) {
+ ddekit_simple_free (cvp);
+}
+
+void ddekit_condvar_wait(ddekit_condvar_t *cvp, ddekit_lock_t *mp) {
+ /* This isn't nice. The encapsulation is broken.
+ * TODO I can merge the two files condvar.c and lock.c. */
+ pthread_cond_wait (&cvp->cond, (pthread_mutex_t *) *mp);
+}
+
+int ddekit_condvar_wait_timed(ddekit_condvar_t *cvp,
+ ddekit_lock_t *mp, int timo) {
+ // TODO currently just let it like this.
+ ddekit_condvar_wait (cvp, mp);
+ return 0;
+}
+
+void ddekit_condvar_signal(ddekit_condvar_t *cvp)
+{
+ pthread_cond_signal (&cvp->cond);
+}
+
+void ddekit_condvar_broadcast(ddekit_condvar_t *cvp) {
+ pthread_cond_broadcast (&cvp->cond);
+}
diff --git a/libddekit/config.h b/libddekit/config.h
new file mode 100644
index 00000000..fdf63562
--- /dev/null
+++ b/libddekit/config.h
@@ -0,0 +1,13 @@
+/**
+ * \file ddekit/include/config.h
+ * \brief Configuration file for ddekit.
+ *
+ * FIXME this file is empty
+ */
+
+#ifndef __ddekit_config_h
+#define __ddekit_config_h
+
+#define DEBUG_MSG(msg, ...) ddekit_printf("%s: \033[35m"msg"\033[0m\n", __FUNCTION__, ##__VA_ARGS__)
+
+#endif /* __ddekit_config_h */
diff --git a/libddekit/dde.h b/libddekit/dde.h
new file mode 100644
index 00000000..12f8a81a
--- /dev/null
+++ b/libddekit/dde.h
@@ -0,0 +1,14 @@
+#ifndef l4_ddekit_h
+#define l4_ddekit_h
+
+/* FIXME if this is ddekit.h, it should be moved into dde/ddekit/include/ddekit.h (also
+ * all headers under include/ddekit) */
+
+/**
+ * Initialize the DDE. Must be called before any other DDE function.
+ *
+ * FIXME revisit this one
+ */
+void ddekit_init(void);
+
+#endif
diff --git a/libddekit/ddekit/assert.h b/libddekit/ddekit/assert.h
new file mode 100644
index 00000000..5d593662
--- /dev/null
+++ b/libddekit/ddekit/assert.h
@@ -0,0 +1,23 @@
+#ifndef _ddekit_assert_h
+#define _ddekit_assert_h
+
+#include "ddekit/printf.h"
+#include "ddekit/panic.h"
+
+/** \file ddekit/assert.h */
+
+/** Assert that an expression is true and panic if not.
+ * \ingroup DDEKit_util
+ */
+#define Assert(expr) do \
+ { \
+ if (!(expr)) { \
+ ddekit_print("\033[31;1mDDE: Assertion failed: "#expr"\033[0m\n"); \
+ ddekit_printf(" File: %s:%d\n",__FILE__,__LINE__); \
+ ddekit_printf(" Function: %s()\n", __FUNCTION__); \
+ ddekit_panic("Assertion failed."); \
+ }} while (0);
+
+#endif
+
+#define assert Assert
diff --git a/libddekit/ddekit/condvar.h b/libddekit/ddekit/condvar.h
new file mode 100644
index 00000000..129a718d
--- /dev/null
+++ b/libddekit/ddekit/condvar.h
@@ -0,0 +1,53 @@
+#ifndef _ddekit_condvar_h
+#define _ddekit_condvar_h
+
+/** \file ddekit/condvar.h */
+#include "ddekit/lock.h"
+
+struct ddekit_condvar;
+typedef struct ddekit_condvar ddekit_condvar_t;
+
+/** Initialize conditional variable.
+ *
+ * \ingroup DDEKit_synchronization
+ */
+ddekit_condvar_t * ddekit_condvar_init(void);
+
+/** Uninitialize conditional variable.
+ *
+ * \ingroup DDEKit_synchronization
+ */
+void ddekit_condvar_deinit(ddekit_condvar_t *cvp);
+
+/** Wait on a conditional variable.
+ *
+ * \ingroup DDEKit_synchronization
+ */
+void ddekit_condvar_wait(ddekit_condvar_t *cvp, ddekit_lock_t *mp);
+
+/** Wait on a conditional variable at most until a timeout expires.
+ *
+ * \ingroup DDEKit_synchronization
+ *
+ * \param cvp pointer to condvar
+ * \param mp lock
+ * \param timo timeout in ms
+ *
+ * \return 0 success
+ * \return !=0 timeout
+ */
+int ddekit_condvar_wait_timed(ddekit_condvar_t *cvp, ddekit_lock_t *mp, int timo);
+
+/** Send signal to the next one waiting for condvar.
+ *
+ * \ingroup DDEKit_synchronization
+ */
+void ddekit_condvar_signal(ddekit_condvar_t *cvp);
+
+/** Send signal to all threads waiting for condvar.
+ *
+ * \ingroup DDEKit_synchronization
+ */
+void ddekit_condvar_broadcast(ddekit_condvar_t *cvp);
+
+#endif
diff --git a/libddekit/ddekit/debug.h b/libddekit/ddekit/debug.h
new file mode 100644
index 00000000..79a8e7b5
--- /dev/null
+++ b/libddekit/ddekit/debug.h
@@ -0,0 +1,8 @@
+#define DDEBUG_QUIET 0
+#define DDEBUG_ERR 1
+#define DDEBUG_WARN 2
+#define DDEBUG_INFO 3
+#define DDEBUG_VERBOSE 4
+
+#define DDEBUG_MEM DDEBUG_INFO
+
diff --git a/libddekit/ddekit/initcall.h b/libddekit/ddekit/initcall.h
new file mode 100644
index 00000000..6befa31c
--- /dev/null
+++ b/libddekit/ddekit/initcall.h
@@ -0,0 +1,42 @@
+#ifndef _ddekit_initcall_h
+#define _ddekit_initcall_h
+
+// from l4/sys/compiler.h
+#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ >= 4
+#define L4_STICKY(x) __attribute__((used)) x
+#else
+#define L4_STICKY(x) __attribute__((unused)) x
+#endif
+
+#define l4str(s) #s
+
+// from dde_linux/ARCH-x86/ctor.h
+typedef void (*l4ddekit_initcall_t)(void);
+
+#define __l4ddekit_initcall(p) \
+ __attribute__ ((__section__ (".l4dde_ctors." #p)))
+
+/** Define a function to be a DDEKit initcall.
+ *
+ * Define a function to be a DDEKit initcall. This function will then be placed
+ * in a separate linker section of the binary (called .l4dde_ctors). The L4Env
+ * construction mechanism will execute all constructors in this section during
+ * application startup.
+ *
+ * This is the right place to place Linux' module_init functions & Co.
+ *
+ * \param fn function
+ */
+#define DDEKIT_INITCALL(fn) DDEKIT_CTOR(fn, 1)
+
+#define DDEKIT_CTOR(fn, prio) \
+ l4ddekit_initcall_t \
+ L4_STICKY(__l4ddekit_initcall_##fn) \
+ __l4ddekit_initcall(prio) = (void *)fn
+
+/**
+ * Runs all registered initcalls.
+ */
+void ddekit_do_initcalls(void);
+
+#endif
diff --git a/libddekit/ddekit/inline.h b/libddekit/ddekit/inline.h
new file mode 100644
index 00000000..e59a5c68
--- /dev/null
+++ b/libddekit/ddekit/inline.h
@@ -0,0 +1,2 @@
+#define INLINE __inline__ __attribute__((always_inline))
+
diff --git a/libddekit/ddekit/interrupt.h b/libddekit/ddekit/interrupt.h
new file mode 100644
index 00000000..3f789210
--- /dev/null
+++ b/libddekit/ddekit/interrupt.h
@@ -0,0 +1,57 @@
+/*
+ * \brief Hardware-interrupt subsystem
+ * \author Thomas Friebel <tf13@os.inf.tu-dresden.de>
+ * \author Christian Helmuth <ch12@os.inf.tu-dresden.de>
+ * \date 2007-01-26
+ *
+ * DDEKit supports registration of one handler function per interrupt. If any
+ * specific DDE implementation needs to register more than one handler,
+ * multiplexing has to be implemented there!
+ */
+
+#ifndef _ddekit_interrupt_h
+#define _ddekit_interrupt_h
+
+#include "ddekit/thread.h"
+
+#define DDEKIT_IRQ_PRIO 2
+
+/**
+ * Attach to hardware interrupt
+ *
+ * \param irq IRQ number to attach to
+ * \param shared set to 1 if interrupt sharing is supported; set to 0
+ * otherwise
+ * \param thread_init called just after DDEKit internal init and before any
+ * other function
+ * \param handler IRQ handler for interrupt irq
+ * \param priv private token (argument for thread_init and handler)
+ *
+ * \return pointer to interrupt thread created
+ */
+ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared,
+ void(*thread_init)(void *),
+ void(*handler)(void *), void *priv);
+
+/**
+ * Detach from a previously attached interrupt.
+ *
+ * \param irq IRQ number
+ */
+void ddekit_interrupt_detach(int irq);
+
+/**
+ * Block interrupt.
+ *
+ * \param irq IRQ number to block
+ */
+void ddekit_interrupt_disable(int irq);
+
+/**
+ * Enable interrupt.
+ *
+ * \param irq IRQ number to block
+ */
+void ddekit_interrupt_enable(int irq);
+
+#endif
diff --git a/libddekit/ddekit/lock.h b/libddekit/ddekit/lock.h
new file mode 100644
index 00000000..dd398b38
--- /dev/null
+++ b/libddekit/ddekit/lock.h
@@ -0,0 +1,83 @@
+#ifndef _ddekit_lock_h
+#define _ddekit_lock_h
+
+struct ddekit_lock;
+
+/** Initialize a DDEKit lock.
+ *
+ * \ingroup DDEKit_synchronization
+ */
+void _ddekit_lock_init (struct ddekit_lock **mtx);
+
+/** Uninitialize a DDEKit lock.
+ *
+ * \ingroup DDEKit_synchronization
+ */
+void _ddekit_lock_deinit (struct ddekit_lock **mtx);
+
+/** Acquire a lock.
+ *
+ * \ingroup DDEKit_synchronization
+ */
+void _ddekit_lock_lock (struct ddekit_lock **mtx);
+
+/** Acquire a lock, non-blocking.
+ *
+ * \ingroup DDEKit_synchronization
+ */
+int _ddekit_lock_try_lock(struct ddekit_lock **mtx);
+
+/** Unlock function.
+ *
+ * \ingroup DDEKit_synchronization
+ */
+void _ddekit_lock_unlock (struct ddekit_lock **mtx);
+
+/** Get lock owner.
+ *
+ * \ingroup DDEKit_synchronization
+ */
+int _ddekit_lock_owner(struct ddekit_lock **mtx);
+
+// definition of ddekit_lock_t
+typedef struct ddekit_lock *ddekit_lock_t;
+
+// common prototypes
+static void ddekit_lock_init_locked(ddekit_lock_t *mtx);
+static void ddekit_lock_init_unlocked(ddekit_lock_t *mtx);
+#define ddekit_lock_init ddekit_lock_init_unlocked
+static void ddekit_lock_deinit (ddekit_lock_t *mtx);
+static void ddekit_lock_lock (ddekit_lock_t *mtx);
+static int ddekit_lock_try_lock(ddekit_lock_t *mtx); // returns 0 on success, != 0 if it would block
+static void ddekit_lock_unlock (ddekit_lock_t *mtx);
+
+// inline implementation or inline call to non-inline implementation
+#include "ddekit/inline.h"
+
+static INLINE void ddekit_lock_init_unlocked(ddekit_lock_t *mtx) {
+ _ddekit_lock_init(mtx);
+}
+
+static INLINE void ddekit_lock_init_locked(ddekit_lock_t *mtx) {
+ _ddekit_lock_init(mtx);
+ _ddekit_lock_lock(mtx);
+}
+
+static INLINE void ddekit_lock_deinit(ddekit_lock_t *mtx) {
+ _ddekit_lock_deinit(mtx);
+}
+static INLINE void ddekit_lock_lock(ddekit_lock_t *mtx) {
+ _ddekit_lock_lock(mtx);
+}
+static INLINE int ddekit_lock_try_lock(ddekit_lock_t *mtx) {
+ return _ddekit_lock_try_lock(mtx);
+}
+static INLINE void ddekit_lock_unlock(ddekit_lock_t *mtx) {
+ _ddekit_lock_unlock(mtx);
+}
+
+static INLINE int ddekit_lock_owner(ddekit_lock_t *mtx) {
+ return _ddekit_lock_owner(mtx);
+}
+
+#endif
diff --git a/libddekit/ddekit/memory.h b/libddekit/ddekit/memory.h
new file mode 100644
index 00000000..051a4d9e
--- /dev/null
+++ b/libddekit/ddekit/memory.h
@@ -0,0 +1,144 @@
+/*
+ * \brief Memory subsystem
+ * \author Thomas Friebel <tf13@os.inf.tu-dresden.de>
+ * \author Christian Helmuth <ch12@os.inf.tu-dresden.de>
+ * \date 2006-11-03
+ */
+
+#ifndef _ddekit_memory_h
+#define _ddekit_memory_h
+
+
+/*******************
+ ** Slab facility **
+ *******************/
+
+struct ddekit_slab;
+
+/**
+ * Store user pointer in slab cache
+ *
+ * \param slab pointer to slab cache
+ * \param data user pointer
+ */
+void ddekit_slab_set_data(struct ddekit_slab * slab, void *data);
+
+/**
+ * Read user pointer from slab cache
+ *
+ * \param slab pointer to slab cache
+ *
+ * \return stored user pointer or 0
+ */
+void *ddekit_slab_get_data(struct ddekit_slab * slab);
+
+/**
+ * Allocate slab in slab cache
+ *
+ * \param slab pointer to slab cache
+ *
+ * \return pointer to allocated slab
+ */
+void *ddekit_slab_alloc(struct ddekit_slab * slab);
+
+/**
+ * Deallocate slab in slab cache
+ *
+ * \param slab pointer to slab cache
+ * \param objp pointer to allocated slab
+ */
+void ddekit_slab_free(struct ddekit_slab * slab, void *objp);
+
+/**
+ * Setup page cache for all slabs
+ *
+ * \param pages maximal number of memory pages
+ *
+ * If 'pages' is too low, memory pages may be given back to the memory server
+ * (dm_phys) and just to be allocated again later. This hits performance (but
+ * saves memory). Increase 'pages' to avoid this thrashing-like effect.
+ *
+ * If the maximal number of unused pages is exceeded, subsequent deallocation
+ * will be freed at the memory server. This page cache caches pages from all
+ * slabs.
+ */
+void ddekit_slab_setup_page_cache(unsigned pages);
+
+/**
+ * Destroy slab cache
+ *
+ * \param slab pointer to slab cache structure
+ */
+void ddekit_slab_destroy(struct ddekit_slab * slab);
+
+/**
+ * Initialize slab cache
+ *
+ * \param size size of cache objects
+ * \param contiguous make this slab use physically contiguous memory
+ *
+ * \return pointer to new slab cache or 0 on error
+ */
+struct ddekit_slab * ddekit_slab_init(unsigned size, int contiguous);
+
+
+/**********************
+ ** Memory allocator **
+ **********************/
+
+/**
+ * Allocate large memory block
+ *
+ * \param size block size
+ * \return pointer to new memory block
+ *
+ * Allocations via this allocator may be slow (because memory servers are
+ * involved) and should be used only for large (i.e., > page size) blocks. If
+ * allocations/deallocations are relatively dynamic this may not be what you
+ * want.
+ *
+ * Allocated blocks have valid virt->phys mappings and are physically
+ * contiguous.
+ */
+void *ddekit_large_malloc(int size);
+
+/**
+ * Free large memory block
+ *
+ * \param p pointer to memory block
+ */
+void ddekit_large_free(void *p);
+
+/** FIXME
+ * contig_malloc() is the lowest-level allocator interface one could implement.
+ * we should consider to provide vmalloc() too. */
+void *ddekit_contig_malloc(
+ unsigned long size,
+ unsigned long low, unsigned long high,
+ unsigned long alignment, unsigned long boundary
+);
+
+
+/*****************************
+ ** Simple memory allocator **
+ *****************************/
+
+/**
+ * Allocate memory block via simple allocator
+ *
+ * \param size block size
+ * \return pointer to new memory block
+ *
+ * The blocks allocated via this allocator CANNOT be used for DMA or other
+ * device operations, i.e., there exists no virt->phys mapping.
+ */
+void *ddekit_simple_malloc(unsigned size);
+
+/**
+ * Free memory block via simple allocator
+ *
+ * \param p pointer to memory block
+ */
+void ddekit_simple_free(void *p);
+
+#endif
diff --git a/libddekit/ddekit/panic.h b/libddekit/ddekit/panic.h
new file mode 100644
index 00000000..1468675f
--- /dev/null
+++ b/libddekit/ddekit/panic.h
@@ -0,0 +1,16 @@
+#ifndef _ddekit_panic_h
+#define _ddekit_panic_h
+
+/** \defgroup DDEKit_util */
+
+/** Panic - print error message and enter the kernel debugger.
+ * \ingroup DDEKit_util
+ */
+void ddekit_panic(char *fmt, ...) __attribute__((noreturn));
+
+/** Print a debug message.
+ * \ingroup DDEKit_util
+ */
+void ddekit_debug(char *fmt, ...);
+
+#endif
diff --git a/libddekit/ddekit/pci.h b/libddekit/ddekit/pci.h
new file mode 100644
index 00000000..5a5fd29b
--- /dev/null
+++ b/libddekit/ddekit/pci.h
@@ -0,0 +1,199 @@
+#ifndef _ddekit_pci_h
+#define _ddekit_pci_h
+
+#include "ddekit/types.h"
+
+/** \defgroup DDEKit_pci */
+
+/** Our version of PCI_ANY_ID */
+#define DDEKIT_PCI_ANY_ID (~0)
+
+/** Copy of L4IO_PCIDEV_RES */
+#define DDEKIT_PCIDEV_RES 12
+
+struct ddekit_pci_dev;
+
+/** PCI resource descriptor. Copied from generic_io.
+ *
+ * XXX!
+ */
+typedef struct ddekit_pci_resource {
+ unsigned long start;
+ unsigned long end;
+ unsigned long flags;
+} ddekit_pci_res_t;
+
+void ddekit_pci_init(void);
+
+int ddekit_pci_get_device(int nr, int *bus, int *slot, int *func);
+
+int ddekit_pci_read(int bus, int slot, int func, int pos, int len, ddekit_uint32_t *val);
+int ddekit_pci_write(int bus, int slot, int func, int pos, int len, ddekit_uint32_t val);
+
+/** Read byte from PCI config space.
+ *
+ * \ingroup DDEKit_pci
+ *
+ * \param bus bus ID
+ * \param slot slot #
+ * \param func function #
+ * \param pos offset in config space
+ * \retval val read value
+ *
+ * \return 0 success
+ */
+int ddekit_pci_readb (int bus, int slot, int func, int pos, ddekit_uint8_t *val);
+
+/** Read word from PCI config space.
+ *
+ * \ingroup DDEKit_pci
+ *
+ * \param bus bus ID
+ * \param slot slot #
+ * \param func function #
+ * \param pos offset in config space
+ * \retval val read value
+ *
+ * \return 0 success
+ */
+int ddekit_pci_readw (int bus, int slot, int func, int pos, ddekit_uint16_t *val);
+
+/** Read dword from PCI config space.
+ *
+ * \ingroup DDEKit_pci
+ *
+ * \param bus bus ID
+ * \param slot slot #
+ * \param func function #
+ * \param pos offset in config space
+ * \retval val read value
+ *
+ * \return 0 success
+ */
+int ddekit_pci_readl (int bus, int slot, int func, int pos, ddekit_uint32_t *val);
+
+/** Write byte to PCI config space.
+ *
+ * \ingroup DDEKit_pci
+ *
+ * \param bus bus ID
+ * \param slot slot #
+ * \param func function #
+ * \param pos offset in config space
+ * \retval val value to write
+ *
+ * \return 0 success
+ */
+int ddekit_pci_writeb(int bus, int slot, int func, int pos, ddekit_uint8_t val);
+
+/** Write word to PCI config space.
+ *
+ * \ingroup DDEKit_pci
+ *
+ * \param bus bus ID
+ * \param slot slot #
+ * \param func function #
+ * \param pos offset in config space
+ * \retval val value to write
+ *
+ * \return 0 success
+ */
+int ddekit_pci_writew(int bus, int slot, int func, int pos, ddekit_uint16_t val);
+
+/** Write word to PCI config space.
+ *
+ * \ingroup DDEKit_pci
+ *
+ * \param bus bus ID
+ * \param slot slot #
+ * \param func function #
+ * \param pos offset in config space
+ * \retval val value to write
+ *
+ * \return 0 success
+ */
+int ddekit_pci_writel(int bus, int slot, int func, int pos, ddekit_uint32_t val);
+
+/** Find a PCI device.
+ *
+ * \ingroup DDEKit_pci
+ *
+ * \param bus pointer to bus number or \ref DDEKIT_PCI_ANY_ID
+ * \param slot pointer to slot number (devfn >> DEVFN_SLOTSHIFT) or \ref DDEKIT_PCI_ANY_ID
+ * \param func pointer to func number (devfc & DEVFN_FUNCMASK) or \ref DDEKIT_PCI_ANY_ID
+ * \param start search device list only behind this device (excluding it!), NULL
+ * searches whole device list
+ *
+ * \retval bus bus number
+ * \retval slot slot number
+ * \retval func function number
+ *
+ * \return device a valid PCI device
+ * \return NULL if no device found
+ */
+struct ddekit_pci_dev *
+ddekit_pci_find_device(int *bus, int *slot, int *func, struct ddekit_pci_dev *start);
+
+/** Enable PCI device
+ * \ingroup DDEKit_pci
+ */
+int ddekit_pci_enable_device(struct ddekit_pci_dev *dev);
+
+/** Disable PCI device
+ * \ingroup DDEKit_pci
+ */
+int ddekit_pci_disable_device(struct ddekit_pci_dev *dev);
+
+/** Enable bus-mastering for device.
+ * \ingroup DDEKit_pci
+ */
+void ddekit_pci_set_master(struct ddekit_pci_dev *dev);
+
+/** Get device vendor ID.
+ * \ingroup DDEKit_pci
+ */
+unsigned short ddekit_pci_get_vendor(struct ddekit_pci_dev *dev);
+
+/** Get device ID.
+ * \ingroup DDEKit_pci
+ */
+unsigned short ddekit_pci_get_device_id(struct ddekit_pci_dev *dev);
+
+/** Get device subvendor ID.
+ * \ingroup DDEKit_pci
+ */
+unsigned short ddekit_pci_get_sub_vendor(struct ddekit_pci_dev *dev);
+
+/** Get subdevice ID.
+ * \ingroup DDEKit_pci
+ */
+unsigned short ddekit_pci_get_sub_device(struct ddekit_pci_dev *dev);
+
+/** Get device class ID.
+ * \ingroup DDEKit_pci
+ */
+unsigned ddekit_pci_get_dev_class(struct ddekit_pci_dev *dev);
+
+/** Get device's IRQ number.
+ * \ingroup DDEKit_pci
+ */
+unsigned long ddekit_pci_get_irq(struct ddekit_pci_dev *dev);
+
+/** Get device name.
+ * \ingroup DDEKit_pci
+ */
+char *ddekit_pci_get_name(struct ddekit_pci_dev *dev);
+
+/** Get device's slot name.
+ * \ingroup DDEKit_pci
+ */
+char *ddekit_pci_get_slot_name(struct ddekit_pci_dev *dev);
+
+/** Get one of the device's resources.
+ * \ingroup DDEKit_pci
+ */
+ddekit_pci_res_t *ddekit_pci_get_resource(struct ddekit_pci_dev *dev, unsigned int idx);
+
+int ddekit_pci_irq_enable(int bus, int slot, int func, int pin, int *irq);
+
+#endif // _ddekit_pci_h
diff --git a/libddekit/ddekit/pgtab.h b/libddekit/ddekit/pgtab.h
new file mode 100644
index 00000000..8964b713
--- /dev/null
+++ b/libddekit/ddekit/pgtab.h
@@ -0,0 +1,86 @@
+/*
+ * \brief Virtual page-table facility
+ * \author Thomas Friebel <tf13@os.inf.tu-dresden.de>
+ * \author Christian Helmuth <ch12@os.inf.tu-dresden.de>
+ * \date 2006-11-03
+ */
+
+#ifndef _ddekit_pgtab_h
+#define _ddekit_pgtab_h
+
+#include "ddekit/types.h"
+
+/* FIXME Region types may be defined by pgtab users. Do we really need them
+ * here? */
+enum ddekit_pgtab_type
+{
+ PTE_TYPE_OTHER, PTE_TYPE_LARGE, PTE_TYPE_UMA, PTE_TYPE_CONTIG
+};
+
+
+/**
+ * Set virtual->physical mapping for VM region
+ *
+ * \param virt virtual start address for region
+ * \param phys physical start address for region
+ * \param pages number of pages in region
+ * \param type pgtab type for region
+ */
+void ddekit_pgtab_set_region(void *virt, ddekit_addr_t phys, int pages, int type);
+
+
+/**
+ * Set virtual->physical mapping for VM region given a specific size in bytes.
+ *
+ * Internally, DDEKit manages regions with pages. However, DDEs do not need to tangle
+ * with the underlying mechanism and therefore can use this function that takes care
+ * of translating a size to an amount of pages.
+ */
+void ddekit_pgtab_set_region_with_size(void *virt, ddekit_addr_t phys, int size, int type);
+
+
+/**
+ * Clear virtual->physical mapping for VM region
+ *
+ * \param virt virtual start address for region
+ * \param type pgtab type for region
+ */
+void ddekit_pgtab_clear_region(void *virt, int type);
+
+/**
+ * Get physical address for virtual address
+ *
+ * \param virt virtual address
+ *
+ * \return physical address
+ */
+ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virt);
+
+/**
+ * Get virtual address for physical address
+ *
+ * \param physical physical address
+ *
+ * \return virtual address
+ */
+ddekit_addr_t ddekit_pgtab_get_virtaddr(const ddekit_addr_t physical);
+
+/**
+ * Get type of VM region.
+ *
+ * \param virt virtual address
+
+ * \return VM region type
+ */
+int ddekit_pgtab_get_type(const void *virt);
+
+/**
+ * Get size of VM region.
+ *
+ * \param virt virtual address
+ *
+ * \return VM region size (in bytes)
+ */
+int ddekit_pgtab_get_size(const void *virt);
+
+#endif
diff --git a/libddekit/ddekit/printf.h b/libddekit/ddekit/printf.h
new file mode 100644
index 00000000..6dafa18d
--- /dev/null
+++ b/libddekit/ddekit/printf.h
@@ -0,0 +1,35 @@
+#ifndef _ddekit_print_h
+#define _ddekit_print_h
+
+#include <stdarg.h>
+
+/** Print message.
+ * \ingroup DDEKit_util
+ */
+int ddekit_print(const char *);
+
+/** Print message with format.
+ * \ingroup DDEKit_util
+ */
+int ddekit_printf(const char *fmt, ...);
+
+/** Print message with format list.
+ * \ingroup DDEKit_util
+ */
+int ddekit_vprintf(const char *fmt, va_list va);
+
+void dump_stack(void);
+
+/** Log function and message.
+ * \ingroup DDEKit_util
+ */
+#define ddekit_log(doit, msg...) \
+ do { \
+ if (doit) { \
+ ddekit_printf("%s(): ", __func__); \
+ ddekit_printf(msg); \
+ ddekit_printf("\n"); \
+ } \
+ } while(0);
+
+#endif
diff --git a/libddekit/ddekit/resources.h b/libddekit/ddekit/resources.h
new file mode 100644
index 00000000..657295a0
--- /dev/null
+++ b/libddekit/ddekit/resources.h
@@ -0,0 +1,14 @@
+#ifndef _ddekit_resources_h
+#define _ddekit_resources_h
+
+#include "ddekit/types.h"
+
+int ddekit_request_dma(int nr);
+int ddekit_release_dma(int nr);
+int ddekit_request_io (ddekit_addr_t start, ddekit_addr_t count);
+int ddekit_release_io (ddekit_addr_t start, ddekit_addr_t count);
+int ddekit_request_mem(ddekit_addr_t start, ddekit_addr_t count, ddekit_addr_t *vaddr);
+int ddekit_release_mem(ddekit_addr_t start, ddekit_addr_t count);
+long ddekit_random (void);
+
+#endif
diff --git a/libddekit/ddekit/semaphore.h b/libddekit/ddekit/semaphore.h
new file mode 100644
index 00000000..c959919d
--- /dev/null
+++ b/libddekit/ddekit/semaphore.h
@@ -0,0 +1,50 @@
+#ifndef _ddekit_semaphore_h
+#define _ddekit_semaphore_h
+
+/** \defgroup DDEKit_synchronization */
+
+struct ddekit_sem;
+typedef struct ddekit_sem ddekit_sem_t;
+
+/** Initialize DDEKit semaphore.
+ *
+ * \ingroup DDEKit_synchronization
+ *
+ * \param value initial semaphore counter
+ */
+ddekit_sem_t *ddekit_sem_init(int value);
+
+/** Uninitialize semaphore.
+ *
+ * \ingroup DDEKit_synchronization
+ */
+void ddekit_sem_deinit(ddekit_sem_t *sem);
+
+/** Semaphore down method. */
+void ddekit_sem_down(ddekit_sem_t *sem);
+
+/** Semaphore down method, non-blocking.
+ *
+ * \ingroup DDEKit_synchronization
+ *
+ * \return 0 success
+ * \return !=0 would block
+ */
+int ddekit_sem_down_try(ddekit_sem_t *sem);
+
+/** Semaphore down with timeout.
+ *
+ * \ingroup DDEKit_synchronization
+ *
+ * \return 0 success
+ * \return !=0 would block
+ */
+int ddekit_sem_down_timed(ddekit_sem_t *sem, int timo);
+
+/** Semaphore up method.
+ *
+ * \ingroup DDEKit_synchronization
+ */
+void ddekit_sem_up(ddekit_sem_t *sem);
+
+#endif
diff --git a/libddekit/ddekit/thread.h b/libddekit/ddekit/thread.h
new file mode 100644
index 00000000..8ed52013
--- /dev/null
+++ b/libddekit/ddekit/thread.h
@@ -0,0 +1,145 @@
+#ifndef _ddekit_thread_h
+#define _ddekit_thread_h
+
+/** \defgroup DDEKit_threads */
+
+#include "ddekit/lock.h"
+
+struct ddekit_thread;
+typedef struct ddekit_thread ddekit_thread_t;
+
+/** Create thread
+ *
+ * \ingroup DDEKit_threads
+ *
+ * Create a new thread running the specified thread function with the specified
+ * arguments. The thread is assigned the given internal name.
+ *
+ * Additionally, DDEKit threads possess a thread-local storage area where they
+ * may store arbitrary data.
+ *
+ * \param fun thread function
+ * \param arg optional argument to thread function, set to NULL if not needed
+ * \param name internal thread name
+ */
+ddekit_thread_t *ddekit_thread_create(void (*fun)(void *), void *arg, const char *name);
+
+/** Reference to own DDEKit thread id.
+ *
+ * \ingroup DDEKit_threads
+ */
+ddekit_thread_t *ddekit_thread_myself(void);
+
+/** Initialize thread with given name.
+ *
+ * \ingroup DDEKit_threads
+ *
+ * This function may be used by threads that were not created using
+ * \ref ddekit_thread_create. This enables such threads to be handled as if they
+ * were DDEKit threads.
+ */
+ddekit_thread_t *ddekit_thread_setup_myself(const char *name);
+
+/** Get TLS data for a specific thread.
+ *
+ * \ingroup DDEKit_threads
+ *
+ * \return Pointer to TLS data of this thread.
+ */
+void *ddekit_thread_get_data(ddekit_thread_t *thread);
+
+/** Get TLS data for current thread.
+ *
+ * \ingroup DDEKit_threads
+ *
+ * Same as calling \ref ddekit_thread_get_data with \ref ddekit_thread_myself
+ * as parameter.
+ *
+ * \return Pointer to TLS data of current thread.
+ */
+void *ddekit_thread_get_my_data(void);
+
+/** Set TLS data for specific thread.
+ *
+ * \ingroup DDEKit_threads
+ *
+ * \param thread DDEKit thread
+ * \param data pointer to thread data
+ */
+void ddekit_thread_set_data(ddekit_thread_t *thread, void *data);
+
+/** Set TLS data for current thread.
+ *
+ * \ingroup DDEKit_threads
+ *
+ * \param data pointer to thread data
+ */
+void ddekit_thread_set_my_data(void *data);
+
+/** Sleep for some miliseconds.
+ *
+ * \ingroup DDEKit_threads
+ *
+ * \param msecs time to sleep in ms.
+ */
+void ddekit_thread_msleep(unsigned long msecs);
+
+/** Sleep for some microseconds.
+ *
+ * \ingroup DDEKit_threads
+ *
+ * \param usecs time to sleep in µs.
+ */
+void ddekit_thread_usleep(unsigned long usecs);
+
+/** Sleep for some nanoseconds.
+ *
+ * \ingroup DDEKit_threads
+ *
+ * \param usecs time to sleep in ns.
+ */
+void ddekit_thread_nsleep(unsigned long nsecs);
+
+/** Sleep until a lock becomes unlocked.
+ *
+ * \ingroup DDEKit_threads
+ */
+void ddekit_thread_sleep(ddekit_lock_t *lock);
+
+/** Wakeup a waiting thread.
+ *
+ * \ingroup DDEKit_threads
+ */
+void ddekit_thread_wakeup(ddekit_thread_t *thread);
+
+/** Terminate a thread
+ *
+ * \ingroup DDEKit_threads
+ */
+void ddekit_thread_exit(void) __attribute__((noreturn));
+
+/** Get the name, a thread registered with DDEKit.
+ *
+ * \ingroup DDEKit_threads
+ */
+const char *ddekit_thread_get_name(ddekit_thread_t *thread);
+
+/** Hint that this thread is done and may be scheduled somehow.
+ *
+ * \ingroup DDEKit_threads
+ */
+void ddekit_thread_schedule(void);
+
+/** Hint that this thread is done and may be scheduled somehow.
+ *
+ * \ingroup DDEKit_threads
+ */
+void ddekit_yield(void);
+
+/** Initialize DDEKit thread subsystem.
+ *
+ * \ingroup DDEKit_threads
+ */
+void ddekit_init_threads(void);
+
+#endif
diff --git a/libddekit/ddekit/timer.h b/libddekit/ddekit/timer.h
new file mode 100644
index 00000000..387f2078
--- /dev/null
+++ b/libddekit/ddekit/timer.h
@@ -0,0 +1,59 @@
+#ifndef _ddekit_timer_h
+#define _ddekit_timer_h
+
+#include "ddekit/thread.h"
+
+#define jiffies (fetch_jiffies())
+#define HZ 100
+
+enum
+{
+ DDEKIT_INVALID_TIMER_ID = -1,
+};
+
+/** \defgroup DDEKit_timer
+ *
+ * Timer subsystem
+ *
+ * DDEKit provides a generic timer implementation that enables users
+ * to execute a function with some arguments after a certain period
+ * of time. DDEKit therefore starts a timer thread that executes these
+ * functions and keeps track of the currently running timers.
+ */
+
+/** Add a timer event. After the absolute timeout has expired, function fn
+ * is called with args as arguments.
+ *
+ * \ingroup DDEKit_timer
+ *
+ * \return >=0 valid timer ID
+ * \return < 0 error
+ */
+int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout);
+
+/** Delete timer with the corresponding timer id.
+ *
+ * \ingroup DDEKit_timer
+ */
+int ddekit_del_timer(int timer);
+
+/** Check whether a timer is pending
+ *
+ * \ingroup DDEKit_timer
+ *
+ * Linux needs this.
+ */
+int ddekit_timer_pending(int timer);
+
+/** Initialization function, startup timer thread
+ *
+ * \ingroup DDEKit_timer
+ */
+void ddekit_init_timers(void);
+
+/** Get the timer thread.
+ */
+ddekit_thread_t *ddekit_get_timer_thread(void);
+extern unsigned long fetch_jiffies (void);
+
+#endif
diff --git a/libddekit/ddekit/types.h b/libddekit/ddekit/types.h
new file mode 100644
index 00000000..83d92c65
--- /dev/null
+++ b/libddekit/ddekit/types.h
@@ -0,0 +1,22 @@
+/*
+ * \brief Types for ddekit (x86 version)
+ * \author Thomas Friebel <tf13@os.inf.tu-dresden.de>
+ * \author Christian Helmuth <ch12@os.inf.tu-dresden.de>
+ * \date 2006-11-09
+ *
+ * FIXME This is definitely arch-dependent! Move to ARCH-something
+ */
+
+#ifndef _DDEKIT_TYPES_H
+#define _DDEKIT_TYPES_H
+
+typedef signed char ddekit_int8_t;
+typedef unsigned char ddekit_uint8_t;
+typedef signed short int ddekit_int16_t;
+typedef unsigned short int ddekit_uint16_t;
+typedef signed int ddekit_int32_t;
+typedef unsigned int ddekit_uint32_t;
+
+typedef unsigned long ddekit_addr_t;
+
+#endif
diff --git a/libddekit/init.c b/libddekit/init.c
new file mode 100644
index 00000000..7caf4c44
--- /dev/null
+++ b/libddekit/init.c
@@ -0,0 +1,31 @@
+/**
+ * The functions regarding DDE/BSD initialization are found here.
+ *
+ * \author Thomas Friebel <tf13@os.inf.tu-dresden.de>
+ */
+#include <error.h>
+#include <mach.h>
+#include <hurd.h>
+
+#include "ddekit/thread.h"
+
+mach_port_t priv_host;
+
+void ddekit_init(void)
+{
+ extern void linux_kmem_init ();
+ extern int log_init ();
+ extern void interrupt_init ();
+ extern int pgtab_init ();
+ error_t err;
+
+ err = get_privileged_ports (&priv_host, NULL);
+ if (err)
+ error (2, err, "get_privileged_ports");
+
+ ddekit_init_threads();
+ pgtab_init ();
+ log_init ();
+ interrupt_init ();
+}
+
diff --git a/libddekit/initcall.c b/libddekit/initcall.c
new file mode 100644
index 00000000..9195243d
--- /dev/null
+++ b/libddekit/initcall.c
@@ -0,0 +1,27 @@
+#include <ddekit/initcall.h>
+
+#define BEG { (crt0_hook) ~1U }
+#define END { (crt0_hook) 0 }
+
+#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ >= 4
+#define SECTION(x) __attribute__((used, section( x )))
+#else
+#define SECTION(x) __attribute__((section( x )))
+#endif
+
+typedef void (*crt0_hook)(void);
+
+static crt0_hook __L4DDE_CTOR_BEG__[1] SECTION(".mark_beg_l4dde_ctors") = BEG;
+static crt0_hook __l4DDE_CTOR_END__[1] SECTION(".mark_end_l4dde_ctors") = END;
+
+void ddekit_do_initcalls() {
+ crt0_hook *list = __L4DDE_CTOR_BEG__;
+
+ list++;
+ while (*list)
+ {
+ (**list)();
+ list++;
+ }
+}
+
diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c
new file mode 100644
index 00000000..940363b1
--- /dev/null
+++ b/libddekit/interrupt.c
@@ -0,0 +1,288 @@
+/*
+ * \brief Hardware-interrupt subsystem
+ * \author Thomas Friebel <tf13@os.inf.tu-dresden.de>
+ * \author Christian Helmuth <ch12@os.inf.tu-dresden.de>
+ * \date 2007-01-22
+ *
+ * FIXME could intloop_param freed after startup?
+ * FIXME use consume flag to indicate IRQ was handled
+ */
+
+#include <stdio.h>
+#include <error.h>
+#include <mach.h>
+#include <hurd.h>
+
+#include "ddekit/interrupt.h"
+#include "ddekit/semaphore.h"
+#include "ddekit/printf.h"
+#include "ddekit/memory.h"
+#include "ddekit/condvar.h"
+
+#include "device_U.h"
+
+#define DEBUG_INTERRUPTS 0
+
+#define MAX_INTERRUPTS 32
+
+#define BLOCK_IRQ 0
+
+#define MACH_INTR_NOTIFY 424242
+
+typedef struct
+{
+ mach_msg_header_t intr_header;
+ mach_msg_type_t intr_type;
+ int line;
+} mach_intr_notification_t;
+
+/*
+ * Internal type for interrupt loop parameters
+ */
+struct intloop_params
+{
+ unsigned irq; /* irq number */
+ int shared; /* irq sharing supported? */
+ void(*thread_init)(void *); /* thread initialization */
+ void(*handler)(void *); /* IRQ handler function */
+ void *priv; /* private token */
+ ddekit_sem_t *started;
+
+ int start_err;
+};
+
+static struct
+{
+ int handle_irq; /* nested irq disable count */
+ ddekit_lock_t irqlock;
+ struct ddekit_condvar *cond;
+ ddekit_thread_t *irq_thread; /* thread ID for detaching from IRQ later on */
+ boolean_t thread_exit;
+ thread_t mach_thread;
+} ddekit_irq_ctrl[MAX_INTERRUPTS];
+
+static mach_port_t master_device;
+static mach_port_t master_host;
+
+/**
+ * Interrupt service loop
+ *
+ */
+static void intloop(void *arg)
+{
+ kern_return_t ret;
+ struct intloop_params *params = arg;
+ mach_port_t delivery_port;
+ mach_port_t pset, psetcntl;
+ int my_index;
+
+ ret = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &delivery_port);
+ if (ret)
+ error (2, ret, "mach_port_allocate");
+
+ my_index = params->irq;
+ ddekit_irq_ctrl[my_index].mach_thread = mach_thread_self ();
+ ret = thread_get_assignment (mach_thread_self (), &pset);
+ if (ret)
+ error (0, ret, "thread_get_assignment");
+ ret = host_processor_set_priv (master_host, pset, &psetcntl);
+ if (ret)
+ error (0, ret, "host_processor_set_priv");
+ thread_max_priority (mach_thread_self (), psetcntl, 0);
+ ret = thread_priority (mach_thread_self (), DDEKIT_IRQ_PRIO, 0);
+ if (ret)
+ error (0, ret, "thread_priority");
+
+ // TODO the flags for shared irq should be indicated by params->shared.
+ // Be careful. For now, we must use shared irq.
+ // Otherwise, the interrupt handler cannot be installed in the kernel.
+ ret = device_intr_register (master_device, params->irq,
+ 0, 0x04000000, delivery_port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ ddekit_printf ("device_intr_register returns %d\n", ret);
+ if (ret) {
+ /* inform thread creator of error */
+ /* XXX does omega0 error code have any meaning to DDEKit users? */
+ params->start_err = ret;
+ ddekit_sem_up(params->started);
+ ddekit_printf ("cannot install irq %d\n", params->irq);
+ return;
+ }
+ device_intr_enable (master_device, params->irq, TRUE);
+
+#if 0
+ /*
+ * Setup an exit fn. This will make sure that we clean up everything,
+ * before shutting down an IRQ thread.
+ */
+ if (l4thread_on_exit(&exit_fn, (void *)my_index) < 0)
+ ddekit_panic("Could not set exit handler for IRQ fn.");
+#endif
+
+ /* after successful initialization call thread_init() before doing anything
+ * else here */
+ if (params->thread_init) params->thread_init(params->priv);
+
+ /* save handle + inform thread creator of success */
+ params->start_err = 0;
+ ddekit_sem_up(params->started);
+
+ int irq_server (mach_msg_header_t *inp, mach_msg_header_t *outp) {
+ mach_intr_notification_t *intr_header = (mach_intr_notification_t *) inp;
+
+ ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
+ if (inp->msgh_id != MACH_INTR_NOTIFY)
+ return 0;
+
+ /* It's an interrupt not for us. It shouldn't happen. */
+ if (intr_header->line != params->irq) {
+ ddekit_printf ("We get interrupt %d, %d is expected",
+ intr_header->line, params->irq);
+ return 1;
+ }
+
+ /* only call registered handler function, if IRQ is not disabled */
+ ddekit_lock_lock (&ddekit_irq_ctrl[my_index].irqlock);
+ while (ddekit_irq_ctrl[my_index].handle_irq <= 0) {
+ ddekit_condvar_wait (ddekit_irq_ctrl[my_index].cond,
+ &ddekit_irq_ctrl[my_index].irqlock);
+ // TODO if it's edged-triggered irq, the interrupt will be lost.
+ }
+ params->handler(params->priv);
+ /* If the irq has been disabled by the linux device,
+ * we don't need to reenable the real one. */
+ device_intr_enable (master_device, my_index, TRUE);
+
+ if (ddekit_irq_ctrl[my_index].thread_exit) {
+ ddekit_lock_unlock (&ddekit_irq_ctrl[my_index].irqlock);
+ ddekit_thread_exit();
+ return 1;
+ }
+ ddekit_lock_unlock (&ddekit_irq_ctrl[my_index].irqlock);
+ return 1;
+ }
+
+ mach_msg_server (irq_server, 0, delivery_port);
+}
+
+
+/**
+ * Attach to hardware interrupt
+ *
+ * \param irq IRQ number to attach to
+ * \param shared set to 1 if interrupt sharing is supported; set to 0
+ * otherwise
+ * \param thread_init called just after DDEKit internal init and before any
+ * other function
+ * \param handler IRQ handler for interrupt irq
+ * \param priv private token (argument for thread_init and handler)
+ *
+ * \return pointer to interrupt thread created
+ */
+ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared,
+ void(*thread_init)(void *),
+ void(*handler)(void *), void *priv)
+{
+ struct intloop_params *params;
+ ddekit_thread_t *thread;
+ char thread_name[10];
+
+ /* We cannot attach the interrupt to the irq which has been used. */
+ if (ddekit_irq_ctrl[irq].irq_thread)
+ return NULL;
+
+ /* initialize info structure for interrupt loop */
+ params = ddekit_simple_malloc(sizeof(*params));
+ if (!params) return NULL;
+
+ // TODO make sure irq is 0-15 instead of 1-16.
+ params->irq = irq;
+ params->thread_init = thread_init;
+ params->handler = handler;
+ params->priv = priv;
+ params->started = ddekit_sem_init(0);
+ params->start_err = 0;
+ params->shared = shared;
+
+ /* construct name */
+ snprintf(thread_name, 10, "irq%02X", irq);
+
+ ddekit_irq_ctrl[irq].handle_irq = 1; /* IRQ nesting level is initially 1 */
+ ddekit_lock_init_unlocked (&ddekit_irq_ctrl[irq].irqlock);
+ ddekit_irq_ctrl[irq].cond = ddekit_condvar_init ();
+ ddekit_irq_ctrl[irq].thread_exit = FALSE;
+
+ /* allocate irq */
+ /* create interrupt loop thread */
+ thread = ddekit_thread_create(intloop, params, thread_name);
+ if (!thread) {
+ ddekit_simple_free(params);
+ return NULL;
+ }
+ ddekit_irq_ctrl[irq].irq_thread = thread;
+
+
+ /* wait for intloop initialization result */
+ ddekit_sem_down(params->started);
+ ddekit_sem_deinit(params->started);
+ if (params->start_err) {
+ ddekit_simple_free(params);
+ return NULL;
+ }
+
+ return thread;
+}
+
+/**
+ * Detach from interrupt by disabling it and then shutting down the IRQ
+ * thread.
+ */
+void ddekit_interrupt_detach(int irq)
+{
+ ddekit_interrupt_disable(irq);
+ // TODO the code should be removed.
+ ddekit_lock_lock (&ddekit_irq_ctrl[irq].irqlock);
+ if (ddekit_irq_ctrl[irq].handle_irq == 0) {
+ ddekit_irq_ctrl[irq].thread_exit = TRUE;
+ ddekit_irq_ctrl[irq].irq_thread = NULL;
+
+ /* If the irq thread is waiting for interrupt notification
+ * messages, thread_abort() can force it to return.
+ * I hope this ugly trick can work. */
+ thread_abort (ddekit_irq_ctrl[irq].mach_thread);
+ }
+ ddekit_lock_unlock (&ddekit_irq_ctrl[irq].irqlock);
+}
+
+
+void ddekit_interrupt_disable(int irq)
+{
+ if (ddekit_irq_ctrl[irq].irqlock) {
+ ddekit_lock_lock (&ddekit_irq_ctrl[irq].irqlock);
+ --ddekit_irq_ctrl[irq].handle_irq;
+ ddekit_lock_unlock (&ddekit_irq_ctrl[irq].irqlock);
+ }
+}
+
+
+void ddekit_interrupt_enable(int irq)
+{
+ if (ddekit_irq_ctrl[irq].irqlock) {
+ ddekit_lock_lock (&ddekit_irq_ctrl[irq].irqlock);
+ ++ddekit_irq_ctrl[irq].handle_irq;
+ if (ddekit_irq_ctrl[irq].handle_irq > 0)
+ ddekit_condvar_signal (ddekit_irq_ctrl[irq].cond);
+ ddekit_lock_unlock (&ddekit_irq_ctrl[irq].irqlock);
+ }
+}
+
+void interrupt_init ()
+{
+
+ error_t err;
+
+ err = get_privileged_ports (&master_host, &master_device);
+ if (err)
+ error (1, err, "get_privileged_ports");
+}
diff --git a/libddekit/list.c b/libddekit/list.c
new file mode 100644
index 00000000..4f163584
--- /dev/null
+++ b/libddekit/list.c
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2009 Free Software Foundation, Inc.
+ Written by Zheng Da.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file implements a double linked list. */
+
+#include "list.h"
+
+void entry_init (struct list *entry)
+{
+ entry->next = entry;
+ entry->prev = entry;
+}
+
+void add_entry_head (struct list *head, struct list *entry)
+{
+ entry->next = head->next;
+ head->next->prev = entry;
+ head->next = entry;
+ entry->prev = head;
+}
+
+void add_entry_end (struct list *head, struct list *entry)
+{
+ entry->next = head;
+ entry->prev = head->prev;
+ head->prev->next = entry;
+ head->prev = entry;
+}
+
+struct list *remove_entry_head (struct list *head)
+{
+ struct list *entry = head->next;
+
+ if (EMPTY_LIST (entry))
+ return NULL;
+
+ remove_entry (entry);
+ return entry;
+}
+
+struct list *remove_entry_end (struct list *head)
+{
+ struct list *entry = head->prev;
+
+ if (EMPTY_LIST (entry))
+ return NULL;
+
+ remove_entry (entry);
+ return entry;
+}
+
+void remove_entry (struct list *entry)
+{
+ entry->next->prev = entry->prev;
+ entry->prev->next = entry->next;
+}
+
diff --git a/libddekit/list.h b/libddekit/list.h
new file mode 100644
index 00000000..e6ee48bc
--- /dev/null
+++ b/libddekit/list.h
@@ -0,0 +1,42 @@
+/*
+ Copyright (C) 2009 Free Software Foundation, Inc.
+ Written by Zheng Da.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __LIST_H__
+#define __LIST_H__
+
+#include <stddef.h>
+
+struct list
+{
+ struct list *next, *prev;
+};
+
+void entry_init (struct list *entry);
+void add_entry_head (struct list *head, struct list *entry);
+void add_entry_end (struct list *head, struct list *entry);
+struct list *remove_entry_head (struct list *head);
+struct list *remove_entry_end (struct list *head);
+void remove_entry (struct list *entry);
+
+#define LIST_HEADER(head) struct list head = {&head, &head}
+#define EMPTY_LIST(head) ((head)->next == (head))
+#define LIST_ENTRY(entry, type, field) ((type *) (((char *) entry) - offsetof (type, field)))
+
+#endif
diff --git a/libddekit/lock.c b/libddekit/lock.c
new file mode 100644
index 00000000..26d5cfc8
--- /dev/null
+++ b/libddekit/lock.c
@@ -0,0 +1,55 @@
+#include <pthread.h>
+
+#include "ddekit/lock.h"
+#include "ddekit/memory.h"
+#include "ddekit/thread.h"
+
+#define DDEKIT_DEBUG_LOCKS 0
+
+struct ddekit_lock {
+ pthread_mutex_t lock;
+ ddekit_thread_t *helder;
+};
+
+void _ddekit_lock_init(struct ddekit_lock **mtx) {
+ struct ddekit_lock *lock;
+
+ lock = (struct ddekit_lock *) ddekit_simple_malloc (sizeof *lock);
+ pthread_mutex_init (&lock->lock, NULL);
+ lock->helder = NULL;
+ *mtx = lock;
+}
+
+void _ddekit_lock_deinit(struct ddekit_lock **mtx) {
+ ddekit_simple_free (*mtx);
+ *mtx = NULL;
+}
+
+void _ddekit_lock_lock(struct ddekit_lock **mtx) {
+ pthread_mutex_lock (&(*mtx)->lock);
+ (*mtx)->helder = ddekit_thread_myself ();
+}
+
+/* returns 0 on success, != 0 if it would block */
+int _ddekit_lock_try_lock(struct ddekit_lock **mtx) {
+ if (!pthread_mutex_trylock (&(*mtx)->lock)) { /* lock succeessfully */
+ (*mtx)->helder = ddekit_thread_myself ();
+ return 0;
+ }
+ return -1;
+}
+
+void _ddekit_lock_unlock(struct ddekit_lock **mtx) {
+ // TODO I wonder if it can cause any trouble.
+ (*mtx)->helder = NULL;
+ pthread_mutex_unlock (&(*mtx)->lock);
+}
+
+
+int _ddekit_lock_owner(struct ddekit_lock **mtx) {
+ /* The return value is the address of the holder.
+ * I hope it will be OK. At least, it is OK
+ * for the current implementation of DDE Linux/BSD */
+ return (int) (*mtx)->helder;
+}
+
diff --git a/libddekit/malloc.c b/libddekit/malloc.c
new file mode 100644
index 00000000..a30cd7b7
--- /dev/null
+++ b/libddekit/malloc.c
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 2009 Free Software Foundation, Inc.
+ Written by Zheng Da.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/**
+ * Allocate memory block via simple allocator
+ *
+ * \param size block size
+ * \return pointer to new memory block
+ *
+ * The blocks allocated via this allocator CANNOT be used for DMA or other
+ * device operations, i.e., there exists no virt->phys mapping.
+ *
+ * Each chunk stores its size in the first word for free() to work.
+ */
+
+#include <stdlib.h>
+
+void *ddekit_simple_malloc(unsigned size)
+{
+ return malloc (size);
+}
+
+
+/**
+ * Free memory block via simple allocator
+ *
+ * \param p pointer to memory block
+ */
+void ddekit_simple_free(void *p)
+{
+ free (p);
+}
diff --git a/libddekit/memory.c b/libddekit/memory.c
new file mode 100644
index 00000000..34b283b3
--- /dev/null
+++ b/libddekit/memory.c
@@ -0,0 +1,278 @@
+/*
+ * \brief Memory subsystem
+ * \author Thomas Friebel <tf13@os.inf.tu-dresden.de>
+ * \author Christian Helmuth <ch12@os.inf.tu-dresden.de>
+ * \date 2006-11-03
+ *
+ * The memory subsystem provides the backing store for DMA-able memory via
+ * large malloc and slabs.
+ *
+ * FIXME check thread-safety and add locks where appropriate
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include "mach_U.h"
+#include <hurd/slab.h>
+
+#include "util.h"
+#include "ddekit/memory.h"
+#include "ddekit/panic.h"
+#include "ddekit/pgtab.h"
+
+#define CACHE_LINE_SIZE 32
+
+/****************
+ ** Page cache **
+ ****************/
+
+/* FIXME revisit two-linked-lists approach - we could get rid of the
+ * pcache_free lists, because these descriptors can also be allocated
+ * whenever the need arises. (XXX: Check how this hurts performance.)
+ */
+
+/*****************************************************************************
+ DDEKit maintains a list of free pages that can be used for growing
+ existing DDEKit slabs. We distinguish between 2 types of pages: the ones
+ that have been allocated from physically contiguous dataspaces and the the
+ ones that have not.
+
+ For each type of cache, we maintain two lists: a list of free pages that
+ can be used to grow a cache (pcache_used) and a list of free pcache entries
+ that can be used to store pages when they get freed (pcache_free). The
+ reason for this is that by using these two lists, cache operations can be
+ done atomically using cmpxchg.
+
+ The function ddekit_slab_setup_page_cache() is used to tune the number of
+ cached pages.
+ ******************************************************************************/
+
+/* page cache to minimize allocations from external servers */
+struct ddekit_pcache
+{
+ struct ddekit_pcache *next;
+ void *page;
+ int contig;
+};
+
+/**
+ * Setup page cache for all slabs
+ *
+ * \param pages maximal number of memory pages
+ *
+ * If the maximal number of unused pages is exceeded, subsequent deallocation
+ * will be freed at the memory server. This page cache caches pages from all
+ * slabs.
+ */
+void ddekit_slab_setup_page_cache(unsigned pages)
+{
+ UNIMPL;
+}
+
+/*******************************
+ ** Slab cache implementation **
+ *******************************/
+
+/* ddekit slab facilitates l4slabs */
+struct ddekit_slab
+{
+ struct hurd_slab_space space;
+};
+
+/**
+ * Allocate object in slab
+ */
+void *ddekit_slab_alloc(struct ddekit_slab * slab)
+{
+ void *buffer;
+ error_t err = hurd_slab_alloc (&slab->space, &buffer);
+ return err ? NULL : buffer;
+}
+
+
+/**
+ * Free object in slab
+ */
+void ddekit_slab_free(struct ddekit_slab * slab, void *objp)
+{
+ hurd_slab_dealloc (&slab->space, objp);
+}
+
+
+/**
+ * Store user pointer in slab cache
+ */
+void ddekit_slab_set_data(struct ddekit_slab * slab, void *data)
+{
+#if 0
+ l4slab_set_data(&slab->cache, data);
+#endif
+ UNIMPL;
+}
+
+
+/**
+ * Read user pointer from slab cache
+ */
+void *ddekit_slab_get_data(struct ddekit_slab * slab)
+{
+#if 0
+ return l4slab_get_data(&slab->cache);
+#endif
+ UNIMPL;
+ return NULL;
+}
+
+
+/**
+ * Destroy slab cache
+ *
+ * \param slab pointer to slab cache structure
+ */
+void ddekit_slab_destroy (struct ddekit_slab * slab)
+{
+ hurd_slab_free ((hurd_slab_space_t) slab);
+}
+
+error_t allocate_buffer (void *hook, size_t size, void **ptr)
+{
+ *ptr = ddekit_large_malloc (size);
+ if (*ptr == NULL)
+ return ENOMEM;
+ return 0;
+}
+
+error_t deallocate_buffer (void *hook, void *buffer, size_t size)
+{
+ ddekit_large_free (buffer);
+ return 0;
+}
+
+/**
+ * Initialize slab cache
+ *
+ * \param size size of cache objects
+ * \param contiguous make this slab use physically contiguous memory
+ *
+ * \return pointer to new slab cache or 0 on error
+ */
+struct ddekit_slab * ddekit_slab_init(unsigned size, int contiguous)
+{
+ struct ddekit_slab * slab;
+ error_t err;
+
+ if (contiguous)
+ err = hurd_slab_create (size, CACHE_LINE_SIZE, allocate_buffer,
+ deallocate_buffer, NULL, NULL, NULL,
+ (hurd_slab_space_t *) &slab);
+ else
+ /* If the object isn't used by DMA,
+ * we can use all default settings. */
+ err = hurd_slab_create (size, 0, NULL, NULL, NULL, NULL, NULL,
+ (hurd_slab_space_t *) &slab);
+ if (err)
+ {
+ error (2, err, "hurd_slab_create");
+ }
+ return slab;
+}
+
+
+/**********************************
+ ** Large block memory allocator **
+ **********************************/
+
+/**
+ * Free large block of memory
+ *
+ * This is no useful for allocation < page size.
+ *
+ * TODO The freed memory can be cached and will be still accessible (
+ * no page fault when accessed). I hope it won't caused any troubles.
+ */
+void ddekit_large_free(void *objp)
+{
+ int err;
+ int size = ddekit_pgtab_get_size (objp);
+ ddekit_pgtab_clear_region (objp, 0);
+ err = munmap (objp, size);
+ if (err < 0)
+ error (0, errno, "munmap");
+}
+
+
+/**
+ * Allocate large block of memory
+ *
+ * This is no useful for allocation < page size.
+ */
+void *ddekit_large_malloc(int size)
+{
+ error_t err;
+ vm_address_t vstart, pstart;
+ extern mach_port_t priv_host;
+
+ /* Allocate memory. */
+ err = vm_allocate_contiguous (priv_host, mach_task_self (),
+ &vstart, &pstart, size);
+ if (err)
+ {
+ error (0, err, "vm_allocate_contiguous");
+ vstart = 0;
+ }
+ else
+ ddekit_pgtab_set_region_with_size ((void *) vstart, pstart, size, 0);
+
+ return (void *) vstart;
+}
+
+
+/**
+ * Allocate large block of memory (special interface)
+ *
+ * This is no useful for allocation < page size.
+ *
+ * FIXME implementation missing...
+ */
+void *ddekit_contig_malloc(unsigned long size,
+ unsigned long low, unsigned long high,
+ unsigned long alignment, unsigned long boundary)
+{
+#if 0
+ void *res;
+ int err;
+ int pages;
+ l4_size_t tmp;
+ l4dm_mem_addr_t dm_paddr;
+
+ size = l4_round_page(size);
+ pages = size >> L4_PAGESHIFT;
+
+ res = l4dm_mem_allocate_named(size, L4DM_CONTIGUOUS | L4DM_PINNED | L4RM_MAP | L4RM_LOG2_ALIGNED);
+
+ if (res) {
+ /* check if res meets low/high/alignment/boundary
+ * and panic if it is not the case
+ * XXXY
+ */
+
+ /* get physical address */
+ err = l4dm_mem_phys_addr(res, 1, &dm_paddr, 1, &tmp);
+ if (err != 1)
+ ddekit_debug("contigmalloc: error getting physical address of new page!\n");
+
+ /* set PTE */
+ ddekit_set_ptes(res, dm_paddr.addr, pages, PTE_TYPE_CONTIG);
+ }
+
+ return res;
+#else
+ ddekit_debug("%s: not implemented\n", __func__);
+ return 0;
+#endif
+}
diff --git a/libddekit/panic.c b/libddekit/panic.c
new file mode 100644
index 00000000..40ba80f4
--- /dev/null
+++ b/libddekit/panic.c
@@ -0,0 +1,28 @@
+#include "ddekit/panic.h"
+#include "ddekit/printf.h"
+
+#include <error.h>
+#include <stdarg.h>
+
+void ddekit_panic(char *fmt, ...) {
+ va_list va;
+
+ va_start(va, fmt);
+ ddekit_vprintf(fmt, va);
+ va_end(va);
+ ddekit_printf("\n");
+
+ error (1, 0, "ddekit_panic()");
+}
+
+void ddekit_debug(char *fmt, ...) {
+ va_list va;
+
+ va_start(va, fmt);
+ ddekit_vprintf(fmt, va);
+ va_end(va);
+ ddekit_printf("\n");
+
+ error (0, 0, "ddekit_debug()");
+}
+
diff --git a/libddekit/pci.c b/libddekit/pci.c
new file mode 100644
index 00000000..ca16b6f9
--- /dev/null
+++ b/libddekit/pci.c
@@ -0,0 +1,405 @@
+#include <stdlib.h>
+#include <error.h>
+#include <string.h>
+#include <pciaccess.h>
+
+#include "ddekit/assert.h"
+#include "ddekit/printf.h"
+#include "ddekit/pci.h"
+#include "config.h"
+
+#define dbg_this 0
+
+/** PCI descriptor */
+typedef struct ddekit_pci_dev {
+ struct pci_device *dev;
+} ddekit_pci_dev_t;
+
+typedef struct ddekit_pci_bus {
+ struct {
+ ddekit_pci_dev_t funs[8];
+ } devs[32];
+} ddekit_pci_bus_t;
+
+#define MAX_NUM_BUSES 256
+
+static int num_pci_devs;
+static ddekit_pci_dev_t *ddekit_pci_devs;
+static ddekit_pci_bus_t *ddekit_pci_buses[MAX_NUM_BUSES];
+
+static inline int invalid_device(ddekit_pci_dev_t *d)
+{
+ return d->dev == NULL;
+}
+
+
+/** Initialize DDEKit PCI module.
+ *
+ * \ingroup DDEKit_pci
+ *
+ * This function builds a list of devices by querying L4IO.
+ */
+void ddekit_pci_init(void)
+{
+ int slots_found = 0;
+ int err;
+ struct pci_device *pci_dev;
+ struct pci_device_iterator *dev_iter;
+
+ err = pci_system_init ();
+ if (err)
+ error (2, err, "pci_system_init");
+
+ num_pci_devs = 32;
+ ddekit_pci_devs = malloc (sizeof (ddekit_pci_devs[0]) * num_pci_devs);
+ memset (ddekit_pci_devs, 0,
+ sizeof (ddekit_pci_devs[0]) * num_pci_devs);
+ dev_iter = pci_slot_match_iterator_create (NULL);
+ while ((pci_dev = pci_device_next (dev_iter)) != NULL) {
+ /* store the device in the structured array. */
+ if (ddekit_pci_buses[pci_dev->bus] == NULL) {
+ ddekit_pci_buses[pci_dev->bus] = calloc (1, sizeof (**ddekit_pci_buses));
+ assert(ddekit_pci_buses[pci_dev->bus] != NULL);
+ }
+ ddekit_pci_buses[pci_dev->bus]->devs[pci_dev->dev].funs[pci_dev->func].dev = pci_dev;
+
+ /* We also put the device in the flat array.
+ * The array is increased dynamically. */
+ if (slots_found >= num_pci_devs) {
+ num_pci_devs *= 2;
+ ddekit_pci_devs = realloc (ddekit_pci_devs,
+ sizeof (ddekit_pci_devs[0])
+ * num_pci_devs);
+ assert (ddekit_pci_devs != NULL);
+ memset (&ddekit_pci_devs[slots_found], 0,
+ (num_pci_devs - slots_found)
+ * sizeof (ddekit_pci_devs[0]));
+ }
+ ddekit_pci_devs[slots_found].dev = pci_dev;
+ ++slots_found;
+ }
+ num_pci_devs = slots_found;
+ pci_iterator_destroy (dev_iter);
+}
+
+
+/**
+ * Get PCI device (bus, slot, func) for handle.
+ *
+ * \ingroup DDEKit_pci
+ */
+int ddekit_pci_get_device(int nr, int *bus, int *slot, int *func)
+{
+ ddekit_pci_dev_t *dev;
+
+ ddekit_printf ("searching for dev #%d", nr);
+
+ if (nr >= 0 && nr < num_pci_devs
+ && !invalid_device(&ddekit_pci_devs[nr])) {
+ dev = &ddekit_pci_devs[nr];
+ *bus = dev->dev->bus;
+ *slot = dev->dev->dev;
+ *func = dev->dev->func;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+ddekit_pci_dev_t *ddekit_pci_find_device(int *bus, int *slot, int *func,
+ ddekit_pci_dev_t *start)
+{
+ Assert(bus);
+ Assert(slot);
+ Assert(func);
+
+ int idx = start ? start->dev->dev + 1 : 0;
+
+ for ( ; idx < num_pci_devs; ++idx) {
+ ddekit_pci_dev_t *dev = &ddekit_pci_devs[idx];
+ if (!invalid_device(dev) &&
+ (*bus == DDEKIT_PCI_ANY_ID || dev->dev->bus == *bus) &&
+ (*slot == DDEKIT_PCI_ANY_ID || dev->dev->dev == *slot) &&
+ (*func == DDEKIT_PCI_ANY_ID || dev->dev->func == *func)) {
+ *bus = dev->dev->bus;
+ *slot = dev->dev->dev;
+ *func = dev->dev->func;
+ return dev;
+ }
+ }
+
+ return NULL;
+}
+
+int ddekit_pci_read(int bus, int slot, int func, int pos, int len, ddekit_uint32_t *val)
+{
+ switch(len)
+ {
+ case 1:
+ return ddekit_pci_readb(bus, slot, func, pos, (ddekit_uint8_t *)val);
+ case 2:
+ return ddekit_pci_readw(bus, slot, func, pos, (ddekit_uint16_t *)val);
+ case 4:
+ return ddekit_pci_readl(bus, slot, func, pos, val);
+ }
+
+ return -1;
+}
+
+int ddekit_pci_write(int bus, int slot, int func, int pos, int len, ddekit_uint32_t val)
+{
+ switch(len)
+ {
+ case 1:
+ return ddekit_pci_writeb(bus, slot, func, pos, val);
+ case 2:
+ return ddekit_pci_writew(bus, slot, func, pos, val);
+ case 4:
+ return ddekit_pci_writel(bus, slot, func, pos, val);
+ }
+
+ return -1;
+}
+
+
+/** Find PCI device for a given (bus, slot, func) tuple.
+*
+* \ingroup DDEKit_pci
+ *
+ * This function is only used internally by the pci_{read,write}{b,l,w} functions.
+ * It was once called pci_find_device, but this caused confusion with the "real"
+ * find_device() functionality provided by L4IO and the Linux PCI subsystem.
+ */
+static inline ddekit_pci_dev_t *ddekit_pci_find_device_fixed(int bus, int slot, int func)
+{
+ ddekit_pci_dev_t *dev;
+
+ /* If the bus doesn't exist. */
+ if (ddekit_pci_buses[bus] == NULL)
+ return NULL;
+
+ dev = &ddekit_pci_buses[bus]->devs[slot].funs[func];
+ if (dev && dev->dev)
+ return dev;
+ return NULL;
+}
+
+
+int ddekit_pci_readb (int bus, int slot, int func, int pos, ddekit_uint8_t *val)
+{
+ ddekit_pci_dev_t *dev = ddekit_pci_find_device_fixed(bus, slot, func);
+ if (dev)
+ return pci_device_cfg_read_u8 (dev->dev, val, pos);
+ else
+ return -1;
+}
+
+
+int ddekit_pci_readw (int bus, int slot, int func, int pos, ddekit_uint16_t *val)
+{
+ ddekit_pci_dev_t *dev = ddekit_pci_find_device_fixed(bus, slot, func);
+ if (dev)
+ return pci_device_cfg_read_u16 (dev->dev, val, pos);
+ else
+ return -1;
+}
+
+
+int ddekit_pci_readl (int bus, int slot, int func, int pos, ddekit_uint32_t *val)
+{
+ ddekit_pci_dev_t *dev = ddekit_pci_find_device_fixed(bus, slot, func);
+ if (dev) {
+ assert (dev->dev != NULL);
+ return pci_device_cfg_read_u32 (dev->dev, val, pos);
+ }
+ else
+ return -1;
+}
+
+
+int ddekit_pci_writeb(int bus, int slot, int func, int pos, ddekit_uint8_t val)
+{
+ ddekit_pci_dev_t *dev = ddekit_pci_find_device_fixed(bus, slot, func);
+ if (dev)
+ return pci_device_cfg_write_u8 (dev->dev, val, pos);
+ else
+ return -1;
+}
+
+
+int ddekit_pci_writew(int bus, int slot, int func, int pos, ddekit_uint16_t val)
+{
+ ddekit_pci_dev_t *dev = ddekit_pci_find_device_fixed(bus, slot, func);
+ if (dev)
+ return pci_device_cfg_write_u16 (dev->dev, val, pos);
+ else
+ return -1;
+}
+
+
+int ddekit_pci_writel(int bus, int slot, int func, int pos, ddekit_uint32_t val)
+{
+ ddekit_pci_dev_t *dev = ddekit_pci_find_device_fixed(bus, slot, func);
+ if (dev)
+ return pci_device_cfg_write_u32 (dev->dev, val, pos);
+ else
+ return -1;
+}
+
+int ddekit_pci_enable_device(struct ddekit_pci_dev *dev)
+{
+ pci_device_enable (dev->dev);
+ return 0;
+}
+
+int ddekit_pci_disable_device(struct ddekit_pci_dev *dev)
+{
+ // TODO
+ return -1;
+}
+
+/********************************************************************************
+ ** Accessor functions for the various kinds of information that are available **
+ ** from struct l4io_pci_dev (which is not handed through to the DDEs, because **
+ ** it still contains L4 types). **
+ ********************************************************************************/
+
+/**
+ * Get PCI device vendor ID.
+ *
+ * \param dev device
+ *
+ * \ingroup DDEKit_pci
+ */
+unsigned short ddekit_pci_get_vendor(struct ddekit_pci_dev *dev)
+{
+ return dev->dev->vendor_id;
+}
+
+
+/**
+ * Get PCI device ID.
+ *
+ * \param dev device
+ *
+ * \ingroup DDEKit_pci
+ */
+unsigned short ddekit_pci_get_device_id(struct ddekit_pci_dev *dev)
+{
+ return dev->dev->device_id;
+}
+
+
+/**
+ * Get PCI device subvendor ID.
+ *
+ * \param dev device
+ *
+ * \ingroup DDEKit_pci
+ */
+unsigned short ddekit_pci_get_sub_vendor(struct ddekit_pci_dev *dev)
+{
+ return dev->dev->subvendor_id;
+}
+
+
+/**
+ * Get PCI device subdevice ID.
+ *
+ * \param dev device
+ *
+ * \ingroup DDEKit_pci
+ */
+unsigned short ddekit_pci_get_sub_device(struct ddekit_pci_dev *dev)
+{
+ return dev->dev->subdevice_id;
+}
+
+
+/**
+ * Get PCI device class ID.
+ *
+ * \param dev device
+ *
+ * \ingroup DDEKit_pci
+ */
+unsigned ddekit_pci_get_dev_class(struct ddekit_pci_dev *dev)
+{
+ return dev->dev->device_class;
+}
+
+
+/**
+ * Get PCI device IRQ number.
+ *
+ * \param dev device
+ *
+ * \ingroup DDEKit_pci
+ */
+unsigned long ddekit_pci_get_irq(struct ddekit_pci_dev *dev)
+{
+ return dev->dev->irq;
+}
+
+
+/**
+ * Get PCI device name.
+ *
+ * \param dev device
+ *
+ * \ingroup DDEKit_pci
+ */
+char *ddekit_pci_get_name(struct ddekit_pci_dev *dev)
+{
+ // TODO
+ return NULL;
+}
+
+
+/**
+ * Get PCI device slot name.
+ *
+ * \param dev device
+ *
+ * \ingroup DDEKit_pci
+ */
+char *ddekit_pci_get_slot_name(struct ddekit_pci_dev *dev)
+{
+ // TODO
+ return NULL;
+}
+
+
+/**
+ * Get PCI device resource at index.
+ *
+ * \param dev device
+ * \param idx resource index
+ *
+ * \ingroup DDEKit_pci
+ */
+ddekit_pci_res_t *ddekit_pci_get_resource(struct ddekit_pci_dev *dev, unsigned int idx)
+{
+ // TODO
+// if (idx > L4IO_PCIDEV_RES)
+ return NULL;
+
+// return (ddekit_pci_res_t *)(&(dev->l4dev.res[idx]));
+}
+
+
+/**
+ * Set PCI bus mastering for device.
+ *
+ * \ingroup DDEKit_pci
+ */
+void ddekit_pci_set_master(struct ddekit_pci_dev *dev)
+{
+ //TODO l4io_pci_set_master(dev->l4dev.handle);
+}
+
+int ddekit_pci_irq_enable(int bus, int slot, int func, int pin, int *irq)
+{
+ return 0;
+}
diff --git a/libddekit/pgtab.c b/libddekit/pgtab.c
new file mode 100644
index 00000000..81138108
--- /dev/null
+++ b/libddekit/pgtab.c
@@ -0,0 +1,213 @@
+/*
+ * \brief Virtual page-table facility
+ * \author Thomas Friebel <tf13@os.inf.tu-dresden.de>
+ * \author Christian Helmuth <ch12@os.inf.tu-dresden.de>
+ * \date 2006-11-01
+ *
+ * This implementation uses l4rm (especially the AVL tree and userptr) to
+ * manage virt->phys mappings. Each mapping region is represented by one
+ * pgtab_object that is kept in the l4rm region userptr.
+ *
+ * For this to work, dataspaces must be attached to l4rm regions!
+ */
+
+#include <unistd.h>
+#include <error.h>
+#include <errno.h>
+#include <mach.h>
+#include <pthread.h>
+
+#include "ddekit/pgtab.h"
+#include "util.h"
+#include "config.h"
+
+/* A structure of recording a region of memory. */
+struct entry
+{
+ void *virtual;
+ ddekit_addr_t physical;
+ int size;
+ int type;
+};
+
+static struct entry *regions;
+/* The number of memory regions in the array REGIONS */
+static int num_regions;
+/* The size of the array REGIONS */
+static int capability;
+static pthread_mutex_t lock;
+#define INIT_SIZE 128
+
+/*****************************
+ ** Page-table facility API **
+ *****************************/
+
+static struct entry *get_entry_from_phys (const ddekit_addr_t phys)
+{
+ int i;
+
+ for (i = 0; i < num_regions; i++)
+ {
+ if (regions[i].physical <= phys
+ && regions[i].physical + regions[i].size > phys)
+ return &regions[i];
+ }
+ return NULL;
+}
+
+static struct entry *get_entry_from_virt (const ddekit_addr_t virt)
+{
+ int i;
+
+ for (i = 0; i < num_regions; i++)
+ {
+ if ((ddekit_addr_t) regions[i].virtual <= virt
+ && ((ddekit_addr_t) regions[i].virtual)
+ + regions[i].size > virt)
+ return &regions[i];
+ }
+ return NULL;
+}
+
+/**
+ * Get physical address for virtual address
+ *
+ * \param virtual virtual address
+ * \return physical address or 0
+ */
+ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virtual)
+{
+ struct entry *e;
+ pthread_mutex_lock (&lock);
+ e = get_entry_from_virt ((ddekit_addr_t) virtual);
+ if (e)
+ {
+ ddekit_addr_t phys = e->physical + (virtual - e->virtual);
+ pthread_mutex_unlock (&lock);
+ return phys;
+ }
+ pthread_mutex_unlock (&lock);
+
+ ddekit_printf ("a virtual address %p doesn't exist.\n", virtual);
+ return -1;
+}
+
+/**
+ * Get virtual address for physical address
+ *
+ * \param physical physical address
+ * \return virtual address or 0
+ */
+ddekit_addr_t ddekit_pgtab_get_virtaddr(const ddekit_addr_t physical)
+{
+ struct entry *e;
+
+ pthread_mutex_lock (&lock);
+ e = get_entry_from_phys (physical);
+ if (e)
+ {
+ ddekit_addr_t virt = (ddekit_addr_t) e->virtual
+ + (physical - e->physical);
+ pthread_mutex_unlock (&lock);
+ return virt;
+ }
+ pthread_mutex_unlock (&lock);
+
+
+ ddekit_printf ("a physical address %p doesn't exist.\n", physical);
+ return -1;
+}
+
+// TODO
+int ddekit_pgtab_get_type(const void *virtual)
+{
+#if 0
+ /* find pgtab object */
+ struct pgtab_object *p = l4rm_get_userptr(virtual);
+ if (!p) {
+ /* XXX this is verbose */
+ LOG_Error("no virt->phys mapping for %p", virtual);
+ return -1;
+ }
+
+ return p->type;
+#endif
+ UNIMPL;
+ return 0;
+}
+
+int ddekit_pgtab_get_size(const void *virtual)
+{
+ struct entry *e;
+ pthread_mutex_lock (&lock);
+ e = get_entry_from_virt ((ddekit_addr_t) virtual);
+ if (e)
+ {
+ int size = e->size;
+ pthread_mutex_unlock (&lock);
+ return size;
+ }
+ pthread_mutex_unlock (&lock);
+ return 0;
+}
+
+
+/**
+ * Clear virtual->physical mapping for VM region
+ *
+ * \param virtual virtual start address for region
+ * \param type pgtab type for region
+ */
+void ddekit_pgtab_clear_region(void *virtual, int type)
+{
+ struct entry *e;
+
+ pthread_mutex_lock (&lock);
+ e = get_entry_from_virt ((ddekit_addr_t) virtual);
+ if (e)
+ {
+ *e = regions[num_regions - 1];
+ num_regions--;
+ }
+ pthread_mutex_unlock (&lock);
+}
+
+
+/**
+ * Set virtual->physical mapping for VM region
+ *
+ * \param virtual virtual start address for region
+ * \param physical physical start address for region
+ * \param pages number of pages in region
+ * \param type pgtab type for region
+ */
+void ddekit_pgtab_set_region(void *virtual, ddekit_addr_t physical, int pages, int type)
+{
+ ddekit_pgtab_set_region (virtual, physical, pages * getpagesize (), type);
+}
+
+void ddekit_pgtab_set_region_with_size(void *virt, ddekit_addr_t phys, int size, int type)
+{
+ pthread_mutex_lock (&lock);
+ if (num_regions == capability)
+ {
+ capability *= 2;
+ regions = realloc (regions, capability * sizeof (struct entry));
+ if (regions == NULL)
+ error (2, errno, "realloc");
+ }
+ regions[num_regions].virtual = virt;
+ regions[num_regions].physical = phys;
+ regions[num_regions].size = size;
+ regions[num_regions].type = type;
+ num_regions++;
+ pthread_mutex_unlock (&lock);
+}
+
+int pgtab_init ()
+{
+ capability = INIT_SIZE;
+ regions = malloc (sizeof (struct entry) * capability);
+ pthread_mutex_init (&lock, NULL);
+ return 0;
+}
diff --git a/libddekit/printf.c b/libddekit/printf.c
new file mode 100644
index 00000000..c4a8b718
--- /dev/null
+++ b/libddekit/printf.c
@@ -0,0 +1,107 @@
+/*
+ * \brief Logging facility with printf()-like interface
+ * \author Thomas Friebel <yaron@yaron.de>
+ * \date 2006-03-01
+ */
+
+#include <error.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <mach.h>
+#include <execinfo.h>
+
+#include "ddekit/printf.h"
+
+extern boolean_t using_std;
+static FILE *output;
+
+/**
+ * Log constant string message w/o arguments
+ *
+ * \param msg message to be logged
+ */
+int ddekit_print(const char *msg)
+{
+ int ret;
+
+ /* If LOG hasn't been initialized or failed its initialization,
+ * return the error. */
+ if (output == NULL)
+ return -1;
+
+ ret = fprintf (output, "%s", msg);
+ if (ret > 0)
+ fflush (output);
+ return ret;
+}
+
+/**
+ * Log message with print()-like arguments
+ *
+ * \param fmt format string followed by optional arguments
+ */
+int ddekit_printf(const char *fmt, ...)
+{
+ int res;
+ va_list va;
+
+ va_start(va, fmt);
+ res = ddekit_vprintf(fmt, va);
+ va_end(va);
+
+ return res;
+}
+
+/* Log message with vprintf()-like arguments
+ *
+ * \param fmt format string
+ * \param va variable argument list
+ */
+int ddekit_vprintf(const char *fmt, va_list va)
+{
+ char *tmp = NULL;
+ int ret;
+
+ ret = vasprintf (&tmp, fmt, va);
+ if (ret > 0) {
+ ret = ddekit_print (tmp);
+ free (tmp);
+ }
+ return ret;
+}
+
+int log_init ()
+{
+ if (using_std) {
+ output = stderr;
+ }
+ else {
+ char template[] = "/var/log/dde_log.XXXXXX";
+ int ret = mkstemp (template);
+ if (ret < 0) {
+ error (0, errno, "mkstemp");
+ return -1;
+ }
+
+ output = fopen (template, "a+");
+ if (!output) {
+ error (0, errno, "open %s", template);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+void dump_stack()
+{
+#define NUM_TRACES 16
+ void *trace[NUM_TRACES];
+ int trace_size = 0;
+
+ fprintf (stderr, "dump the stack\n");
+ trace_size = backtrace(trace, NUM_TRACES);
+ backtrace_symbols_fd(trace, trace_size, 2);
+}
diff --git a/libddekit/resources.c b/libddekit/resources.c
new file mode 100644
index 00000000..45704378
--- /dev/null
+++ b/libddekit/resources.c
@@ -0,0 +1,125 @@
+#include <stdlib.h>
+#include <error.h>
+#include <sys/io.h>
+#include <mach.h>
+#include <hurd.h>
+#include <device/device.h>
+
+#include "ddekit/resources.h"
+
+#include "config.h"
+
+int ddekit_request_dma(int nr) {
+#if 0
+ return l4io_request_dma(nr);
+#endif
+ return -1;
+}
+
+int ddekit_release_dma(int nr) {
+#if 0
+ return l4io_release_dma(nr);
+#endif
+ return -1;
+}
+
+/** Request an IO region
+ *
+ * \return 0 success
+ * \return -1 error
+ */
+int ddekit_request_io(ddekit_addr_t start, ddekit_addr_t count) {
+ return ioperm (start, count, 1);
+}
+
+/** Release an IO region.
+ *
+ * \return 0 success
+ * \return <0 error
+ */
+int ddekit_release_io(ddekit_addr_t start, ddekit_addr_t count) {
+ return ioperm (start, count, 0);
+}
+
+/* Get a memory object for the whole physical address space. */
+static memory_object_t get_physmem_object(void)
+{
+ mach_port_t master_device_port;
+ mach_port_t iopl_dev;
+ memory_object_t obj;
+ kern_return_t err;
+
+ /* first open master device port */
+ err = get_privileged_ports(NULL, &master_device_port);
+ if (err)
+ error(2, err, "get_physmem_object() can't get master device port");
+
+ /* now use it to open iopl device */
+ err = device_open(master_device_port, VM_PROT_READ | VM_PROT_WRITE, "mem", &iopl_dev);
+ if (err)
+ error(2, err, "get_physmem_object() can't open iopl device");
+
+ mach_port_deallocate(mach_task_self(), master_device_port);
+
+ /* now use that to get a memory object for the physical address space */
+ err = device_map(iopl_dev, D_READ|D_WRITE, 0, ~0, &obj, 0);
+ if (err)
+ error(2, err, "get_physmem_object() can't obtain memory object");
+
+ mach_port_deallocate(mach_task_self(), iopl_dev);
+
+ return obj;
+}
+
+/** Request a memory region.
+ *
+ * \return vaddr virtual address of memory region
+ * \return 0 success
+ * \return -1 error
+ */
+int ddekit_request_mem(ddekit_addr_t start, ddekit_addr_t count, ddekit_addr_t *vaddr) {
+ memory_object_t iopl_mem;
+ kern_return_t err;
+ *vaddr = 0;
+
+ iopl_mem = get_physmem_object();
+
+ err = vm_map(mach_task_self(),
+ (vm_address_t *) vaddr,
+ count,
+ 0, /* mask */
+ 1, /* anywhere */
+ iopl_mem,
+ (vm_offset_t)start,
+ 0, /* copy on write */
+ VM_PROT_READ|VM_PROT_WRITE,
+ VM_PROT_READ|VM_PROT_WRITE,
+ VM_INHERIT_SHARE);
+ mach_port_deallocate(mach_task_self(),iopl_mem);
+ if( err )
+ {
+ error(0, err, "mmio_map(): can't vm_map");
+ return -1;
+ }
+ return 0;
+}
+
+/** Release memory region.
+ *
+ * \return 0 success
+ * \return <0 error
+ */
+int ddekit_release_mem(ddekit_addr_t start, ddekit_addr_t count) {
+ kern_return_t err = vm_deallocate(mach_task_self(), start, count);
+ if( err )
+ {
+ error(0, err, "mmio_unmap(): can't dealloc mmio space");
+ return -1;
+ }
+ return 0;
+}
+
+long ddekit_random ()
+{
+ return random ();
+}
diff --git a/libddekit/thread.c b/libddekit/thread.c
new file mode 100644
index 00000000..8f7b3ed9
--- /dev/null
+++ b/libddekit/thread.c
@@ -0,0 +1,434 @@
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <time.h>
+#include <error.h>
+#include <mach.h>
+#include <hurd.h>
+#include <sys/time.h>
+#include <assert.h>
+
+#include "ddekit/memory.h"
+#include "ddekit/semaphore.h"
+#include "ddekit/condvar.h"
+#include "list.h"
+#include "ddekit/thread.h"
+
+#define DDEKIT_THREAD_STACK_SIZE 0x2000 /* 8 KB */
+
+//static struct ddekit_slab *ddekit_stack_slab = NULL;
+
+struct _ddekit_private_data {
+ struct list list;
+ ddekit_condvar_t *sleep_cond;
+ /* point to the thread who has the private data. */
+ struct ddekit_thread *thread;
+ mach_msg_header_t wakeupmsg;
+};
+
+struct ddekit_thread {
+ pthread_t thread;
+ char *name;
+ struct _ddekit_private_data *private;
+ void *user;
+};
+
+struct ddekit_sem
+{
+ pthread_spinlock_t lock;
+ /* A list of thread waiting for the semaphore. */
+ struct list head;
+ int value;
+};
+
+static __thread struct ddekit_thread *thread_self;
+
+static void _thread_cleanup ()
+{
+ mach_port_destroy (mach_task_self (),
+ thread_self->private->wakeupmsg.msgh_remote_port);
+ ddekit_condvar_deinit (thread_self->private->sleep_cond);
+ ddekit_simple_free (thread_self->private);
+ ddekit_simple_free (thread_self->name);
+ ddekit_simple_free (thread_self);
+}
+
+/* Prepare a wakeup message. */
+static error_t _create_wakeupmsg (struct _ddekit_private_data *data)
+{
+ kern_return_t err;
+
+ /* Build wakeup message. */
+ data->wakeupmsg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0);
+ data->wakeupmsg.msgh_size = 0;
+
+ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &data->wakeupmsg.msgh_remote_port);
+ if (err)
+ return EAGAIN;
+
+ data->wakeupmsg.msgh_local_port = MACH_PORT_NULL;
+ data->wakeupmsg.msgh_seqno = 0;
+ data->wakeupmsg.msgh_id = 0;
+
+ err = mach_port_insert_right (mach_task_self (),
+ data->wakeupmsg.msgh_remote_port,
+ data->wakeupmsg.msgh_remote_port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (err) {
+ mach_port_destroy (mach_task_self (),
+ data->wakeupmsg.msgh_remote_port);
+ return EAGAIN;
+ }
+
+ return 0;
+}
+
+static void setup_thread (struct ddekit_thread *t, const char *name) {
+ error_t err;
+ struct _ddekit_private_data *private_data;
+
+ if (name) {
+ char *cpy = NULL;
+
+ cpy = ddekit_simple_malloc (strlen (name) + 1);
+ if (cpy == NULL)
+ error (0, 0, "fail to allocate memory");
+ else
+ strcpy (cpy, name);
+
+ t->name = cpy;
+ }
+
+ private_data = (struct _ddekit_private_data *)
+ ddekit_simple_malloc (sizeof (*private_data));
+
+ private_data->sleep_cond = ddekit_condvar_init ();
+ private_data->list.prev = &private_data->list;
+ private_data->list.next = &private_data->list;
+ private_data->thread = t;
+
+ err = _create_wakeupmsg (private_data);
+ if (err)
+ error (1, err, "_create_wakeupmsg");
+
+ t->private = private_data;
+}
+
+ddekit_thread_t *ddekit_thread_setup_myself(const char *name) {
+ ddekit_thread_t *td = (ddekit_thread_t *) malloc (sizeof (*td));
+ setup_thread (td, name);
+ thread_self = td;
+ return td;
+}
+
+typedef struct
+{
+ void (*fun)(void *);
+ void *arg;
+ struct ddekit_thread *td;
+ pthread_cond_t cond;
+ pthread_mutex_t lock;
+ int status;
+} priv_arg_t;
+
+static void* _priv_fun (void *arg)
+{
+ priv_arg_t *priv_arg = arg;
+ thread_self = priv_arg->td;
+ /* We wait until the initialization of the thread is finished. */
+ pthread_mutex_lock (&priv_arg->lock);
+ while (!priv_arg->status)
+ pthread_cond_wait (&priv_arg->cond, &priv_arg->lock);
+ pthread_mutex_unlock (&priv_arg->lock);
+
+ priv_arg->fun(priv_arg->arg);
+ free (priv_arg->arg);
+ _thread_cleanup ();
+ return NULL;
+}
+
+ddekit_thread_t *ddekit_thread_create(void (*fun)(void *), void *arg, const char *name) {
+ ddekit_thread_t *td = (ddekit_thread_t *) malloc (sizeof (*td));
+ setup_thread (td, name);
+
+ priv_arg_t *priv_arg = (priv_arg_t *) malloc (sizeof (*priv_arg));
+ priv_arg->fun = fun;
+ priv_arg->arg = arg;
+ priv_arg->td = td;
+ pthread_cond_init (&priv_arg->cond, NULL);
+ pthread_mutex_init (&priv_arg->lock, NULL);
+ priv_arg->status = 0;
+
+ pthread_create (&td->thread, NULL, _priv_fun, priv_arg);
+ pthread_detach (td->thread);
+
+ /* Tell the new thread that initialization has been finished. */
+ pthread_mutex_lock (&priv_arg->lock);
+ priv_arg->status = 1;
+ pthread_cond_signal (&priv_arg->cond);
+ pthread_mutex_unlock (&priv_arg->lock);
+
+ return td;
+}
+
+ddekit_thread_t *ddekit_thread_myself(void) {
+ return thread_self;
+}
+
+void ddekit_thread_set_data(ddekit_thread_t *thread, void *data) {
+ thread->user = data;
+}
+
+void ddekit_thread_set_my_data(void *data) {
+ ddekit_thread_set_data(ddekit_thread_myself(), data);
+}
+
+void *ddekit_thread_get_data(ddekit_thread_t *thread) {
+ return thread->user;
+}
+
+void *ddekit_thread_get_my_data() {
+ return ddekit_thread_get_data(ddekit_thread_myself());
+}
+
+void ddekit_thread_msleep(unsigned long msecs) {
+ int ret;
+ struct timespec rgt;
+
+ rgt.tv_sec = (time_t) (msecs / 1000);
+ rgt.tv_nsec = (msecs % 1000) * 1000 * 1000;
+ ret = nanosleep (&rgt , NULL);
+ if (ret < 0)
+ error (0, errno, "nanosleep");
+}
+
+void ddekit_thread_usleep(unsigned long usecs) {
+ int ret;
+ struct timespec rgt;
+
+ rgt.tv_sec = (time_t) (usecs / 1000 / 1000);
+ rgt.tv_nsec = (usecs % (1000 * 1000)) * 1000;
+ ret = nanosleep (&rgt , NULL);
+ if (ret < 0)
+ error (0, errno, "nanosleep");
+}
+
+
+void ddekit_thread_nsleep(unsigned long nsecs) {
+ int ret;
+ struct timespec rgt;
+
+ rgt.tv_sec = (time_t) (nsecs / 1000 / 1000 / 1000);
+ rgt.tv_nsec = nsecs % (1000 * 1000 * 1000);
+ ret = nanosleep (&rgt , NULL);
+ if (ret < 0)
+ error (0, errno, "nanosleep");
+}
+
+void ddekit_thread_sleep(ddekit_lock_t *lock) {
+ // TODO pthread_cond_wait cannot guarantee that the thread is
+ // woke up by another thread, maybe by signals.
+ // Does it matter here?
+ // If it does, use pthread_hurd_cond_wait_np.
+ ddekit_condvar_wait (thread_self->private->sleep_cond, lock);
+}
+
+void ddekit_thread_wakeup(ddekit_thread_t *td) {
+ if (td->private == NULL)
+ return;
+ ddekit_condvar_signal (td->private->sleep_cond);
+}
+
+void ddekit_thread_exit() {
+ _thread_cleanup ();
+ pthread_exit (NULL);
+}
+
+const char *ddekit_thread_get_name(ddekit_thread_t *thread) {
+ return thread->name;
+}
+
+void ddekit_thread_schedule(void)
+{
+ swtch_pri (0);
+}
+
+void ddekit_yield(void)
+{
+ swtch_pri (0);
+}
+
+void ddekit_init_threads() {
+ ddekit_thread_setup_myself ("main");
+}
+
+/**********************************************************************
+ * semaphore
+ **********************************************************************/
+
+/* Block THREAD. */
+static error_t _timedblock (struct _ddekit_private_data *data,
+ const int timeout)
+{
+ error_t err;
+ mach_msg_header_t msg;
+
+ assert (timeout > 0);
+
+ err = mach_msg (&msg, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0,
+ sizeof msg, data->wakeupmsg.msgh_remote_port,
+ timeout, MACH_PORT_NULL);
+ if (err == EMACH_RCV_TIMED_OUT)
+ return ETIMEDOUT;
+
+ assert_perror (err);
+ return 0;
+}
+
+/* Block THREAD. */
+static void _block (struct _ddekit_private_data *data)
+{
+ mach_msg_header_t msg;
+ error_t err;
+
+ err = mach_msg (&msg, MACH_RCV_MSG, 0, sizeof msg,
+ data->wakeupmsg.msgh_remote_port,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ assert_perror (err);
+}
+
+static int _sem_timedwait_internal (ddekit_sem_t *restrict sem,
+ const int timeout)
+{
+ pthread_spin_lock (&sem->lock);
+ if (sem->value > 0) {
+ /* Successful down. */
+ sem->value --;
+ pthread_spin_unlock (&sem->lock);
+ return 0;
+ }
+
+ if (timeout < 0) {
+ pthread_spin_unlock (&sem->lock);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Add ourselves to the queue. */
+ add_entry_head (&sem->head, &thread_self->private->list);
+ pthread_spin_unlock (&sem->lock);
+
+ /* Block the thread. */
+ if (timeout) {
+ error_t err;
+
+ err = _timedblock (thread_self->private, timeout);
+ if (err) {
+ /* We timed out. We may need to disconnect ourself from the
+ waiter queue.
+
+ FIXME: What do we do if we get a wakeup message before we
+ disconnect ourself? It may remain until the next time we
+ block. */
+ assert (err == ETIMEDOUT);
+
+ pthread_spin_lock (&sem->lock);
+ remove_entry (&thread_self->private->list);
+ pthread_spin_unlock (&sem->lock);
+
+ errno = err;
+ return -1;
+ }
+ }
+ else
+ _block (thread_self->private);
+
+ return 0;
+}
+
+/* Wakeup THREAD. */
+static void _thread_wakeup (struct _ddekit_private_data *data)
+{
+ error_t err;
+
+ err = mach_msg (&data->wakeupmsg, MACH_SEND_MSG,
+ sizeof (data->wakeupmsg), 0, MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ assert_perror (err);
+}
+
+ddekit_sem_t *ddekit_sem_init(int value) {
+ ddekit_sem_t *sem =
+ (ddekit_sem_t *) ddekit_simple_malloc (sizeof (*sem));
+
+ sem->lock = PTHREAD_SPINLOCK_INITIALIZER;
+ sem->head.prev = &sem->head;
+ sem->head.next = &sem->head;
+ sem->value = value;
+ return sem;
+}
+
+void ddekit_sem_deinit(ddekit_sem_t *sem) {
+ if (!EMPTY_LIST (&sem->head)) {
+ error (0, EBUSY, "ddekit_sem_deinit");
+ }
+ else
+ ddekit_simple_free(sem);
+}
+
+void ddekit_sem_down(ddekit_sem_t *sem) {
+ _sem_timedwait_internal (sem, 0);
+}
+
+/* returns 0 on success, != 0 when it would block */
+int ddekit_sem_down_try(ddekit_sem_t *sem) {
+ pthread_spin_lock (&sem->lock);
+ if (sem->value > 0) {
+ /* Successful down. */
+ sem->value --;
+ pthread_spin_unlock (&sem->lock);
+ return 0;
+ }
+ pthread_spin_unlock (&sem->lock);
+
+ return -1;
+}
+
+/* returns 0 on success, != 0 on timeout */
+int ddekit_sem_down_timed(ddekit_sem_t *sem, int timo) {
+ /* wait for up to timo milliseconds */
+ return _sem_timedwait_internal (sem, timo);
+}
+
+void ddekit_sem_up(ddekit_sem_t *sem) {
+ struct _ddekit_private_data *wakeup;
+
+ pthread_spin_lock (&sem->lock);
+ if (sem->value > 0) {
+ /* Do a quick up. */
+ assert (EMPTY_LIST (&sem->head));
+ sem->value ++;
+ pthread_spin_unlock (&sem->lock);
+ return;
+ }
+
+ if (EMPTY_LIST (&sem->head)) {
+ /* No one waiting. */
+ sem->value = 1;
+ pthread_spin_unlock (&sem->lock);
+ return;
+ }
+
+ /* Wake someone up. */
+
+ /* First dequeue someone. */
+ wakeup = LIST_ENTRY (remove_entry_end (&sem->head),
+ struct _ddekit_private_data, list);
+
+ /* Then drop the lock and transfer control. */
+ pthread_spin_unlock (&sem->lock);
+ if (wakeup)
+ _thread_wakeup (wakeup);
+}
+
diff --git a/libddekit/timer.c b/libddekit/timer.c
new file mode 100644
index 00000000..169f867c
--- /dev/null
+++ b/libddekit/timer.c
@@ -0,0 +1,342 @@
+#include <error.h>
+#include <maptime.h>
+#include <stdio.h>
+
+#include "ddekit/lock.h"
+#include "ddekit/memory.h"
+#include "ddekit/assert.h"
+#include "ddekit/semaphore.h"
+#include "ddekit/timer.h"
+
+#define __DEBUG 0
+
+volatile struct mapped_time_value *mapped_time;
+long long root_jiffies;
+
+/* Just to remind BjoernD of what this is:
+ * HZ = clock ticks per second
+ * jiffies = clock ticks counter.
+ *
+ * So, if someone schedules a timeout to expire in 2 seconds,
+ * this expires date will be in jiffies + 2 * HZ.
+ */
+
+typedef struct _timer
+{
+ struct _timer *next;
+ void (*fn)(void *);
+ void *args;
+ unsigned long expires;
+ int id;
+} ddekit_timer_t;
+
+
+static ddekit_timer_t *timer_list = NULL; ///< list of pending timers
+static ddekit_lock_t timer_lock; ///< lock to access timer_list
+static ddekit_thread_t *timer_thread_ddekit = NULL; ///< ddekit ID of timer thread
+static ddekit_sem_t *notify_semaphore = NULL; ///< timer thread's wait semaphore
+
+static int timer_id_ctr = 0;
+
+static void dump_list(char *msg)
+{
+#if __DEBUG
+ ddekit_timer_t *l = timer_list;
+
+ ddekit_printf("-=-=-=-= %s =-=-=-\n", msg);
+ while (l) {
+ ddekit_printf("-> %d (%lld)\n", l->id, l->expires);
+ l = l->next;
+ }
+ ddekit_printf("-> NULL\n");
+ ddekit_printf("-=-=-=-=-=-=-=-\n");
+#endif
+}
+
+unsigned long fetch_jiffies ()
+{
+ struct timeval tv;
+ long long j;
+
+ if (mapped_time == NULL)
+ ddekit_init_timers ();
+ maptime_read (mapped_time, &tv);
+
+ j = (long long) tv.tv_sec * HZ + ((long long) tv.tv_usec * HZ) / 1000000;
+ return j - root_jiffies;
+}
+
+/** Notify the timer thread there is a new timer at the beginning of the
+ * timer list.
+ */
+static inline void __notify_timer_thread(void)
+{
+ /* Do not notify if there is no timer thread.
+ * XXX: Perhaps we should better assert that there is a timer
+ * thread before allowing users to add a timer.
+ */
+ if (timer_thread_ddekit == NULL)
+ return;
+
+ ddekit_sem_up(notify_semaphore);
+}
+
+
+int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout)
+{
+ ddekit_timer_t *it;
+ ddekit_timer_t *t = ddekit_simple_malloc(sizeof(ddekit_timer_t));
+
+ Assert(t);
+
+ /* fill in values */
+ t->fn = fn;
+ t->args = args;
+ t->expires = timeout;
+ t->next = NULL;
+
+ ddekit_lock_lock (&timer_lock);
+
+ t->id = timer_id_ctr++;
+
+ /* the easy case... */
+ if (timer_list == NULL || timer_list->expires >= t->expires) {
+ t->next = timer_list;
+ timer_list = t;
+ }
+ else { /* find where to insert */
+ it = timer_list;
+ while (it->next && it->next->expires < t->expires)
+ it = it->next;
+
+ if (it->next) { /* insert somewhere in the middle */
+ t->next = it->next;
+ it->next = t;
+ }
+ else /* we append */
+ it->next = t;
+ }
+
+ /*
+ * if we modified the first entry of the list, it is
+ * necessary to notify the timer thread.
+ */
+ if (t == timer_list) {
+ Assert(timer_thread_ddekit);
+ __notify_timer_thread();
+ }
+
+ ddekit_lock_unlock (&timer_lock);
+
+ dump_list("after add");
+
+ return t->id;
+}
+
+
+int ddekit_del_timer(int timer)
+{
+ ddekit_timer_t *it, *it_next;
+ int ret = -1;
+
+ ddekit_lock_lock (&timer_lock);
+
+ /* no timer? */
+ if (!timer_list) {
+ ret = -2;
+ goto out;
+ }
+
+ /* removee is first item, simply delete it */
+ if (timer_list->id == timer) {
+ it = timer_list->next;
+ ret = timer_list->id;
+ ddekit_simple_free(timer_list);
+ timer_list = it;
+
+ /*
+ * We do not notify the timer thread here to save IPCs. The
+ * thread will wakeup later and finally detect that there is
+ * no timer pending anymore.
+ */
+ goto out;
+ }
+
+ it = timer_list;
+ it_next = it->next;
+
+ /* more difficult if removee is somewhere in
+ * the middle of the list
+ */
+ while (it_next) {
+ if (it_next->id == timer) {
+ it->next = it->next->next;
+ ret = it_next->id;
+ ddekit_simple_free(it_next);
+ goto out;
+ }
+ it = it->next;
+ it_next = it->next;
+ }
+
+out:
+ ddekit_lock_unlock (&timer_lock);
+
+ dump_list("after del");
+
+ return ret;
+}
+
+
+/** Check whether a timer with a given ID is still pending.
+ *
+ * \param timer Timer ID to check for.
+ * \return 0 if not pending
+ * 1 if timer is pending
+ */
+int ddekit_timer_pending(int timer)
+{
+ ddekit_timer_t *t = NULL;
+ int r = 0;
+
+ ddekit_lock_lock (&timer_lock);
+
+ t = timer_list;
+ while (t) {
+ if (t->id == timer) {
+ r = 1;
+ break;
+ }
+ t = t->next;
+ }
+
+ ddekit_lock_unlock (&timer_lock);
+
+ return r;
+}
+
+
+/** Get the next timer function to run.
+ *
+ * \return NULL if no timer is to be run now
+ * != NULL next timer to execute
+ */
+static ddekit_timer_t *get_next_timer(void)
+{
+ ddekit_timer_t *t = NULL;
+
+ /* This function must be called with the timer_lock held. */
+ Assert(ddekit_lock_owner (&timer_lock) == (int) timer_thread_ddekit);
+
+ if (timer_list &&
+ (timer_list->expires <= jiffies)) {
+ t = timer_list;
+ timer_list = timer_list->next;
+ }
+
+ return t;
+}
+
+enum
+{
+ DDEKIT_TIMEOUT_NEVER = 0xFFFFFFFF,
+};
+
+/** Let the timer thread sleep for a while.
+ *
+ * \param to timeout in msec
+ *
+ * \return 1 if IPC timed out
+ * 0 if message received -> recalc timeout
+ */
+static inline int __timer_sleep(unsigned to)
+{
+ int err = 0;
+
+ ddekit_lock_unlock (&timer_lock);
+
+ if (to == DDEKIT_TIMEOUT_NEVER) {
+ ddekit_sem_down(notify_semaphore);
+ }
+ else {
+#if 0
+ ddekit_printf("Going to sleep for %lu µs (%lu ms)\n", to * 1000, to);
+#endif
+ err = ddekit_sem_down_timed(notify_semaphore, to);
+#if 0
+ ddekit_printf("err: %x\n", err);
+#endif
+ }
+
+ ddekit_lock_lock (&timer_lock);
+
+ return (err ? 1 : 0);
+}
+
+
+static void ddekit_timer_thread(void *arg)
+{
+ notify_semaphore = ddekit_sem_init(0);
+#if 0
+ l4thread_set_prio(l4thread_myself(), 0x11);
+#endif
+
+// l4thread_started(0);
+
+ ddekit_lock_lock (&timer_lock);
+ while (1) {
+ ddekit_timer_t *timer = NULL;
+ unsigned long to = DDEKIT_TIMEOUT_NEVER;
+
+ if (timer_list) {
+#if 0
+ int jdiff = timer_list->expires - jiffies;
+ ddekit_printf("\033[31mscheduling new timeout.\033[0m\n");
+ ddekit_printf("\033[31mjiffies diff = %ld (%d s)\033[0m\n", jdiff, jdiff/HZ);
+#endif
+ to = (timer_list->expires - jiffies) * 1000000 / HZ;
+ to /= 1000;
+ }
+
+ __timer_sleep(to);
+
+ while ((timer = get_next_timer()) != NULL) {
+ ddekit_lock_unlock (&timer_lock);
+ //ddekit_printf("doing timer fn @ %p\n", timer->fn);
+ timer->fn(timer->args);
+ ddekit_simple_free(timer);
+ ddekit_lock_lock (&timer_lock);
+ }
+ }
+ // TODO how is the thread terminated?
+}
+
+ddekit_thread_t *ddekit_get_timer_thread()
+{
+ return timer_thread_ddekit;
+}
+
+
+void ddekit_init_timers(void)
+{
+ error_t err;
+ struct timeval tp;
+ static int initialized = 0;
+
+ if (initialized)
+ return;
+
+ initialized = 1;
+ err = maptime_map (0, 0, &mapped_time);
+ if (err)
+ error (2, err, "cannot map time device");
+
+ maptime_read (mapped_time, &tp);
+
+ root_jiffies = (long long) tp.tv_sec * HZ
+ + ((long long) tp.tv_usec * HZ) / 1000000;
+
+ ddekit_lock_init (&timer_lock);
+ timer_thread_ddekit = ddekit_thread_create (ddekit_timer_thread,
+ NULL, "ddekit_timer");
+}
diff --git a/libddekit/util.h b/libddekit/util.h
new file mode 100644
index 00000000..02bcc6f0
--- /dev/null
+++ b/libddekit/util.h
@@ -0,0 +1,8 @@
+#ifndef __UTIL_H__
+#define __UTIL_H__
+
+#include "ddekit/printf.h"
+
+#define UNIMPL ddekit_printf("%s is unimplemented\n", __func__);
+
+#endif
diff --git a/libddekit/vm_param.h b/libddekit/vm_param.h
new file mode 100644
index 00000000..7b615c8a
--- /dev/null
+++ b/libddekit/vm_param.h
@@ -0,0 +1,7 @@
+#ifndef __VM_PARAM_H__
+#define __VM_PARAM_H__
+
+#define PAGE_SIZE __vm_page_size
+#define PAGE_MASK (PAGE_SIZE-1)
+
+#endif