diff options
-rw-r--r-- | libddekit/Makefile | 9 | ||||
-rw-r--r-- | libddekit/condvar.c | 108 | ||||
-rw-r--r-- | libddekit/config.h | 13 | ||||
-rw-r--r-- | libddekit/init.c | 35 | ||||
-rw-r--r-- | libddekit/initcall.c | 8 | ||||
-rw-r--r-- | libddekit/interrupt.c | 229 | ||||
-rw-r--r-- | libddekit/lock.c | 62 | ||||
-rw-r--r-- | libddekit/malloc.c | 94 | ||||
-rw-r--r-- | libddekit/memory.c | 467 | ||||
-rw-r--r-- | libddekit/panic.c | 29 | ||||
-rw-r--r-- | libddekit/pci.c | 392 | ||||
-rw-r--r-- | libddekit/pgtab-old.c | 219 | ||||
-rw-r--r-- | libddekit/pgtab.c | 219 | ||||
-rw-r--r-- | libddekit/printf.c | 46 | ||||
-rw-r--r-- | libddekit/resources.c | 57 | ||||
-rw-r--r-- | libddekit/semaphore.c | 48 | ||||
-rw-r--r-- | libddekit/thread.c | 195 | ||||
-rw-r--r-- | libddekit/timer.c | 329 |
18 files changed, 2559 insertions, 0 deletions
diff --git a/libddekit/Makefile b/libddekit/Makefile new file mode 100644 index 00000000..67d58733 --- /dev/null +++ b/libddekit/Makefile @@ -0,0 +1,9 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +# the default is to build the listed directories, provided that they +# contain a Makefile. If you need to change this, uncomment the following +# line and adapt it. +# TARGET = idl src lib server examples doc + +include $(L4DIR)/mk/subdir.mk diff --git a/libddekit/condvar.c b/libddekit/condvar.c new file mode 100644 index 00000000..a495cf92 --- /dev/null +++ b/libddekit/condvar.c @@ -0,0 +1,108 @@ +/** + * Unchecked (no BSD invariants) condition variable implementation for + * dde-internal use. Written from scratch. + * + * \author Thomas Friebel <tf13@os.inf.tu-dresden.de> + */ +#include <l4/dde/ddekit/condvar.h> +#include <l4/dde/ddekit/lock.h> +#include <l4/dde/ddekit/memory.h> + +#include <l4/log/l4log.h> +#include <l4/semaphore/semaphore.h> +#include <l4/lock/lock.h> + +struct ddekit_condvar { + unsigned waiters; + unsigned signals; + l4lock_t lock; + l4semaphore_t sem; + l4semaphore_t handshake; +}; + +ddekit_condvar_t *ddekit_condvar_init() { + ddekit_condvar_t *cvp; + + cvp = ddekit_simple_malloc(sizeof(*cvp)); + + cvp->waiters = 0; + cvp->signals = 0; + cvp->lock = L4LOCK_UNLOCKED; + cvp->sem = L4SEMAPHORE_INIT(0); + cvp->handshake = L4SEMAPHORE_INIT(0); + + return cvp; +} + +void ddekit_condvar_wait(ddekit_condvar_t *cvp, ddekit_lock_t *mp) { + ddekit_condvar_wait_timed(cvp, mp, -1); +} + +int ddekit_condvar_wait_timed(ddekit_condvar_t *cvp, ddekit_lock_t *mp, int timo) { + int rval; + + l4lock_lock(&cvp->lock); + cvp->waiters++; + l4lock_unlock(&cvp->lock); + + ddekit_lock_unlock(mp); + + if (timo == -1) { + l4semaphore_down(&cvp->sem); + rval = 0; + } else { + rval = l4semaphore_down_timed(&cvp->sem, timo); + } + + l4lock_lock(&cvp->lock); + if (cvp->signals > 0) { + /* if we timed out, but there is a signal now, consume it */ + if (rval) l4semaphore_down(&cvp->sem); + + l4semaphore_up(&cvp->handshake); + cvp->signals--; + } + cvp->waiters--; + l4lock_unlock(&cvp->lock); + + ddekit_lock_lock(mp); + + return rval; +} + +void ddekit_condvar_signal(ddekit_condvar_t *cvp) +{ + l4lock_lock(&cvp->lock); + + if (cvp->waiters > cvp->signals) { + cvp->signals++; + l4semaphore_up(&cvp->sem); + l4lock_unlock(&cvp->lock); + l4semaphore_down(&cvp->handshake); + } else { + /* nobody left to wakeup */ + l4lock_unlock(&cvp->lock); + } +} + +void ddekit_condvar_broadcast(ddekit_condvar_t *cvp) { + int waiters; + + l4lock_lock(&cvp->lock); + + waiters = cvp->waiters - cvp->signals; + if (waiters > 0) { + int i; + + cvp->signals = cvp->waiters; + for (i=0; i<waiters; i++) { + l4semaphore_up(&cvp->sem); + } + l4lock_unlock(&cvp->lock); + for (i=0; i<waiters; i++) { + l4semaphore_down(&cvp->handshake); + } + } else { + l4lock_unlock(&cvp->lock); + } +} 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/init.c b/libddekit/init.c new file mode 100644 index 00000000..0532caed --- /dev/null +++ b/libddekit/init.c @@ -0,0 +1,35 @@ +/** + * The functions regarding DDE/BSD initialization are found here. + * + * \author Thomas Friebel <tf13@os.inf.tu-dresden.de> + */ +#include <l4/dde/ddekit/panic.h> +#include <l4/dde/ddekit/thread.h> +#include <l4/dde/ddekit/memory.h> + +#include <l4/dde/dde.h> +#include <l4/log/l4log.h> +#include <l4/env/errno.h> +#include <l4/generic_io/libio.h> + +/* FIXME this must be initialized explicitly as some users may not need l4io, + * e.g., l4io's own pcilib. */ +static void ddekit_init_l4io(void) +{ + int err; + l4io_info_t *ioip = NULL; + + LOGd(0, "mapping io info page to %p", ioip); + err = l4io_init(&ioip, L4IO_DRV_INVALID); + if ( err | !ioip ) { + LOG("error initializing io lib: %s (err=%d, ioip=%p)", l4env_errstr(err), err, ioip); + ddekit_panic("fatal error"); + } +} + +void ddekit_init(void) +{ + ddekit_init_l4io(); + ddekit_init_threads(); +} + diff --git a/libddekit/initcall.c b/libddekit/initcall.c new file mode 100644 index 00000000..49e1fec1 --- /dev/null +++ b/libddekit/initcall.c @@ -0,0 +1,8 @@ +#include <l4/dde/ddekit/initcall.h> + +#include <l4/crtx/crt0.h> + +void ddekit_do_initcalls() { + crt0_dde_construction(); +} + diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c new file mode 100644 index 00000000..557611a6 --- /dev/null +++ b/libddekit/interrupt.c @@ -0,0 +1,229 @@ +/* + * \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 <l4/dde/ddekit/interrupt.h> +#include <l4/dde/ddekit/semaphore.h> +#include <l4/dde/ddekit/thread.h> +#include <l4/dde/ddekit/memory.h> +#include <l4/dde/ddekit/panic.h> + +#include <l4/omega0/client.h> +#include <l4/log/l4log.h> +#include <l4/thread/thread.h> + +#include <stdio.h> + +#define DEBUG_INTERRUPTS 0 + +#define MAX_INTERRUPTS 32 + +#define BLOCK_IRQ 0 + +/* + * 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_sem_t *irqsem; /* synch semaphore */ + ddekit_thread_t *irq_thread; /* thread ID for detaching from IRQ later on */ + omega0_irqdesc_t irq_desc; /* Omega0-style IRQ descriptor */ +} ddekit_irq_ctrl[MAX_INTERRUPTS]; + + +static void ddekit_irq_exit_fn(l4thread_t thread, void *data) +{ + int idx = (int)data; + + // * detach from IRQ + omega0_detach(ddekit_irq_ctrl[idx].irq_desc); +} + +L4THREAD_EXIT_FN_STATIC(exit_fn, ddekit_irq_exit_fn); + + +/** + * Interrupt service loop + * + */ +static void intloop(void *arg) +{ + struct intloop_params *params = arg; + + l4thread_set_prio(l4thread_myself(), DDEKIT_IRQ_PRIO); + + omega0_request_t req = { .i = 0 }; + int o0handle; + int my_index = params->irq; + omega0_irqdesc_t *desc = &ddekit_irq_ctrl[my_index].irq_desc; + + /* setup interrupt descriptor */ + desc->s.num = params->irq + 1; + desc->s.shared = params->shared; + + /* allocate irq */ + o0handle = omega0_attach(*desc); + if (o0handle < 0) { + /* inform thread creator of error */ + /* XXX does omega0 error code have any meaning to DDEKit users? */ + params->start_err = o0handle; + ddekit_sem_up(params->started); + return; + } + + /* + * 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."); + + /* 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); + + /* prepare request structure */ + req.s.param = params->irq + 1; + req.s.wait = 1; + req.s.consume = 0; + req.s.unmask = 1; + + while (1) { + int err; + + /* wait for int */ + err = omega0_request(o0handle, req); + if (err != params->irq + 1) + LOG("omega0_request returned %d, %d (irq+1) expected", err, params->irq + 1); + + LOGd(DEBUG_INTERRUPTS, "received irq 0x%X", err - 1); + + /* unmask only the first time */ + req.s.unmask = 0; + + /* only call registered handler function, if IRQ is not disabled */ + ddekit_sem_down(ddekit_irq_ctrl[my_index].irqsem); + if (ddekit_irq_ctrl[my_index].handle_irq > 0) { + LOGd(DEBUG_INTERRUPTS, "IRQ %x, handler %p", my_index,params->handler); + params->handler(params->priv); + } + else + LOGd(DEBUG_INTERRUPTS, "not handling IRQ %x, because it is disabled.", my_index); + + ddekit_sem_up(ddekit_irq_ctrl[my_index].irqsem); + LOGd(DEBUG_INTERRUPTS, "after irq handler"); + } +} + + +/** + * 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]; + + /* initialize info structure for interrupt loop */ + params = ddekit_simple_malloc(sizeof(*params)); + if (!params) return NULL; + + 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); + + /* create interrupt loop thread */ + thread = ddekit_thread_create(intloop, params, thread_name); + if (!thread) { + ddekit_simple_free(params); + return NULL; + } + + ddekit_irq_ctrl[irq].handle_irq = 1; /* IRQ nesting level is initially 1 */ + ddekit_irq_ctrl[irq].irq_thread = thread; + ddekit_irq_ctrl[irq].irqsem = ddekit_sem_init(1); + + + /* 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); + ddekit_thread_terminate(ddekit_irq_ctrl[irq].irq_thread); +} + + +void ddekit_interrupt_disable(int irq) +{ + if (ddekit_irq_ctrl[irq].irqsem) { + ddekit_sem_down(ddekit_irq_ctrl[irq].irqsem); + --ddekit_irq_ctrl[irq].handle_irq; + ddekit_sem_up(ddekit_irq_ctrl[irq].irqsem); + } +} + + +void ddekit_interrupt_enable(int irq) +{ + if (ddekit_irq_ctrl[irq].irqsem) { + ddekit_sem_down(ddekit_irq_ctrl[irq].irqsem); + ++ddekit_irq_ctrl[irq].handle_irq; + ddekit_sem_up(ddekit_irq_ctrl[irq].irqsem); + } +} diff --git a/libddekit/lock.c b/libddekit/lock.c new file mode 100644 index 00000000..0f451dfd --- /dev/null +++ b/libddekit/lock.c @@ -0,0 +1,62 @@ +#include <l4/dde/ddekit/lock.h> +#include <l4/dde/ddekit/memory.h> + +#include <l4/lock/lock.h> +#include <l4/util/macros.h> + +#define DDEKIT_DEBUG_LOCKS 0 + +struct ddekit_lock { + l4lock_t lock; +}; + +void _ddekit_lock_init(struct ddekit_lock **mtx) { + *mtx = (struct ddekit_lock *) ddekit_simple_malloc(sizeof(struct ddekit_lock)); + (*mtx)->lock = L4LOCK_UNLOCKED; +} + +void _ddekit_lock_deinit(struct ddekit_lock **mtx) { + ddekit_simple_free(*mtx); + *mtx = NULL; +} + +void _ddekit_lock_lock(struct ddekit_lock **mtx) { +#if DDEKIT_DEBUG_LOCKS + if (&(*mtx)->lock == 0x35ac) + LOG("DOWN %p: "l4util_idfmt" <-> "l4util_idfmt, + &(*mtx)->lock, + l4util_idstr(l4_myself()), + l4util_idstr(l4thread_l4_id(l4lock_owner(&((*mtx)->lock))))); +#endif + l4lock_lock(&(*mtx)->lock); +#if DDEKIT_DEBUG_LOCKS + if (&(*mtx)->lock == 0x35ac) + LOG("DOWN %p! "l4util_idfmt, &(*mtx)->lock, l4util_idstr(l4_myself())); +#endif +} + +/* returns 0 on success, != 0 if it would block */ +int _ddekit_lock_try_lock(struct ddekit_lock **mtx) { + return l4lock_try_lock(&(*mtx)->lock) ? 0 : 1; +} + +void _ddekit_lock_unlock(struct ddekit_lock **mtx) { +#if DDEKIT_DEBUG_LOCKS + if (&(*mtx)->lock == 0x35ac) + LOG("UP %p: "l4util_idfmt" <-> "l4util_idfmt, + &(*mtx)->lock, + l4util_idstr(l4_myself()), + l4util_idstr(l4thread_l4_id(l4lock_owner(&((*mtx)->lock))))); +#endif + l4lock_unlock(&(*mtx)->lock); +#if DDEKIT_DEBUG_LOCKS + if (&(*mtx)->lock == 0x35ac) + LOG("UP %p! "l4util_idfmt, &(*mtx)->lock, l4util_idstr(l4_myself())); +#endif +} + + +int _ddekit_lock_owner(struct ddekit_lock **mtx) { + return (int)l4lock_owner(&(*mtx)->lock); +} + diff --git a/libddekit/malloc.c b/libddekit/malloc.c new file mode 100644 index 00000000..5f0ae0fc --- /dev/null +++ b/libddekit/malloc.c @@ -0,0 +1,94 @@ +/* + * \brief Simple allocator implementation + * \author Christian Helmuth + * \date 2006-10-30 + * + * This simple allocator provides malloc() and free() using dm_mem dataspaces + * as backing store. The actual list-based allocator implementation is from + * l4util resp. Fiasco. + * + * For large allocations and slab-based OS-specific allocators + * ddekit_large_malloc and ddekit_slab_*() should be used. The blocks + * allocated via this allocator CANNOT be used for DMA or other device + * operations, i.e., there exists no virt->phys mapping. + * + * FIXME check thread-safety and add locks where appropriate + */ + +#include <l4/dde/ddekit/memory.h> +#include <l4/dde/ddekit/printf.h> +#include <l4/dde/ddekit/panic.h> + +#include <l4/sys/consts.h> +#include <l4/util/list_alloc.h> +#include <l4/dm_mem/dm_mem.h> +#include <l4/lock/lock.h> + +/* configuration */ +#define ALLOC_SIZE (4 * L4_PAGESIZE) + +/* malloc pool is a list allocator */ +static l4la_free_t *malloc_pool; +static l4lock_t malloc_lock = L4LOCK_UNLOCKED; + + +/** + * 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. + */ +void *ddekit_simple_malloc(unsigned size) +{ + l4lock_lock(&malloc_lock); + /* we store chunk size in the first word of the chunk */ + size += sizeof(unsigned); + + /* try to allocate */ + unsigned *p = l4la_alloc(&malloc_pool, size, 0); + + /* fill pool if allocation fails */ + if (!p) { + /* size of allocated dataspace is at least ALLOC_SIZE */ + unsigned ds_size = l4_round_page(size); + ds_size = (ds_size > ALLOC_SIZE) ? ds_size : ALLOC_SIZE; + + void *res = l4dm_mem_allocate_named(ds_size, L4RM_MAP, "ddekit malloc"); + if (!res) + p = NULL; + else + { + l4la_free(&malloc_pool, res, ds_size); + p = l4la_alloc(&malloc_pool, size, 0); + } + } + + /* store chunk size */ + if (p) { + *p = size; + p++; + } + + l4lock_unlock(&malloc_lock); + return p; +} + + +/** + * Free memory block via simple allocator + * + * \param p pointer to memory block + */ +void ddekit_simple_free(void *p) +{ + l4lock_lock(&malloc_lock); + unsigned *chunk = (unsigned *)p - 1; + if (p) + l4la_free(&malloc_pool, chunk, *chunk); + l4lock_unlock(&malloc_lock); +} diff --git a/libddekit/memory.c b/libddekit/memory.c new file mode 100644 index 00000000..b6db0cac --- /dev/null +++ b/libddekit/memory.c @@ -0,0 +1,467 @@ +/* + * \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 <l4/dde/ddekit/memory.h> +#include <l4/dde/ddekit/panic.h> +#include <l4/dde/ddekit/pgtab.h> +#include <l4/dde/ddekit/printf.h> + +#include <l4/lock/lock.h> +#include <l4/slab/slab.h> +#include <l4/dm_mem/dm_mem.h> +#include <l4/util/atomic.h> +#include <l4/util/util.h> + + +/**************** + ** 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; +}; + + +/* head of single-linked list containing used page-cache entries, non-contiguous */ +static struct ddekit_pcache *pcache_used; +/* head of single-linked list containing free page-cache entries, non-contiguous */ +static struct ddekit_pcache *pcache_free; + +/* head of single-linked list containing used page-cache entries, contiguous */ +static struct ddekit_pcache *pcache_used_contig; +/* head of single-linked list containing free page-cache entries, contiguous */ +static struct ddekit_pcache *pcache_free_contig; + +/* maximum number of pages to cache. defaults to a minimum of 1 page + * because having none hits the performance too hard. */ +static l4_uint32_t pcache_num_entries = 1; + + +/** + * 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) +{ + /* FIXME just allowing to grow at the moment */ + while (pcache_num_entries < pages) { + struct ddekit_pcache *new_entry, *new_contig; + + /* create new list element */ + new_entry = (struct ddekit_pcache *) ddekit_simple_malloc(sizeof(*new_entry)); + new_contig = (struct ddekit_pcache *) ddekit_simple_malloc(sizeof(*new_contig)); + + /* insert into lists of unused cache entries */ + do { + new_entry->next = pcache_free; + } while (!l4util_cmpxchg32((l4_uint32_t*)&pcache_free, + (l4_uint32_t)new_entry->next, + (l4_uint32_t)new_entry)); + + do { + new_contig->next = pcache_free_contig; + } while (!l4util_cmpxchg32((l4_uint32_t*)&pcache_free_contig, + (l4_uint32_t)new_entry->next, + (l4_uint32_t)new_entry)); + + /* increment number of list elements */ + l4util_inc32(&pcache_num_entries); + } +} + + +/** + * Try to allocate a new page from the pcache. + */ +static inline struct ddekit_pcache *_try_from_cache(int contig) +{ + struct ddekit_pcache *head = NULL; + struct ddekit_pcache *the_cache = contig ? pcache_used_contig : pcache_used; + + do { + head = the_cache; + if (!head) break; + } while (!l4util_cmpxchg32((l4_uint32_t*)&the_cache, (l4_uint32_t)head, + (l4_uint32_t)head->next)); + + return head; +} + + +static inline void _add_to_cache(struct ddekit_pcache *entry, int contig) +{ + struct ddekit_pcache *the_cache = contig ? pcache_used_contig : pcache_used; + do { + entry->next = the_cache; + } while (! l4util_cmpxchg32((l4_uint32_t*)&the_cache, (l4_uint32_t)entry->next, + (l4_uint32_t)entry)); +} + +/** + * Return free entry to cached entry list. + */ +static inline void _free_cache_entry(struct ddekit_pcache *entry, int contig) +{ + struct ddekit_pcache *the_cache = contig ? pcache_free_contig : pcache_free; + do { + entry->next = the_cache; + } while (!l4util_cmpxchg32((l4_uint32_t*)&the_cache, (l4_uint32_t)entry->next, + (l4_uint32_t)entry)); +} + + +static inline struct ddekit_pcache *_get_free_cache_entry(int contig) +{ + struct ddekit_pcache *the_cache = contig ? pcache_free_contig : pcache_free; + struct ddekit_pcache *head = NULL; + + do { + head = the_cache; + if (!head) break; + } while (!l4util_cmpxchg32((l4_uint32_t*)&the_cache, (l4_uint32_t)head, + (l4_uint32_t) head->next)); + + return head; +} + + +/******************************* + ** Slab cache implementation ** + *******************************/ + +/* ddekit slab facilitates l4slabs */ +struct ddekit_slab +{ + l4slab_cache_t cache; + /* + * Lock to prevent concurrent access to the slab's grow() and + * shrink() functions. + */ + l4lock_t lock; + int contiguous; +}; + + +/** + * Get the ddekit slab for a given L4 slab. + * + * We cheat here, because we know that the L4 slab is the first member + * of the ddekit slab. + */ +static inline struct ddekit_slab *ddekit_slab_from_l4slab(l4slab_cache_t *s) +{ + return (struct ddekit_slab *)s; +} + +/** + * Grow slab cache + */ +static void *_slab_grow(l4slab_cache_t *cache, void **data) +{ + /* the page(s) to be returned */ + void *res = NULL; + /* whether this cache needs physically contiguous pages */ + int is_contig = ddekit_slab_from_l4slab(cache)->contiguous; + + /* free cache entry, will be used afterwards */ + struct ddekit_pcache *head = NULL; + + /* We don't reuse pages for slabs > 1 page, because this makes caching + * somewhat harder. */ + if (cache->slab_size <= L4_PAGESIZE) + /* try to aquire cached page */ + head = _try_from_cache(is_contig); + + if (head) { + /* use cached page */ + res = head->page; + /* this cache entry is now available */ + _free_cache_entry(head, is_contig); + } else { + /* allocate new page at memory server */ + int err; + l4_size_t tmp; + l4dm_mem_addr_t dm_paddr; + int num_pages = cache->slab_size / L4_PAGESIZE; + int flags = L4DM_PINNED | L4RM_MAP | L4RM_LOG2_ALIGNED; + + if (is_contig) + flags |= L4DM_CONTIGUOUS; + + /* allocate and map new page(s) */ + res = l4dm_mem_allocate_named(num_pages * L4_PAGESIZE, + flags, + "ddekit slab"); + if (res == NULL) + ddekit_debug("__grow: error allocating a new page"); + + /* physically contiguous pages need some special treatment */ + if (is_contig) { + err = l4dm_mem_phys_addr(res, num_pages, &dm_paddr, 1, &tmp); + if (err != 1) + ddekit_debug("__grow: error getting physical address of new page!"); + + ddekit_pgtab_set_region(res, dm_paddr.addr, num_pages, PTE_TYPE_UMA); + } + } + + /* save pointer to cache in page for ddekit_slab_get_slab() */ + *data = cache; + + return res; +} + +/** + * Shrink slab cache + */ +static void _slab_shrink(l4slab_cache_t *cache, void *page, void *data) +{ + /* cache deallocated page here */ + struct ddekit_pcache *head = NULL; + /* whether this cache needs physically contiguous pages */ + int is_contig = ddekit_slab_from_l4slab(cache)->contiguous; + + /* we do not return slabs to the page cache, if they are larger than one page */ + if (cache->slab_size <= L4_PAGESIZE) + /* try to aquire free cache entry */ + head = _get_free_cache_entry(is_contig); + + if (head) { + /* use free cache entry to cache page */ + + /* set the page info */ + head->page = page; + + /* this cache entry contains a free page */ + _add_to_cache(head, is_contig); + } else { + /* cache is full */ + + if (is_contig) + /* unset pte */ + ddekit_pgtab_clear_region(page, PTE_TYPE_UMA); + + /* free page */ + l4dm_mem_release(page); + } +} + + +/** + * Allocate object in slab + */ +void *ddekit_slab_alloc(struct ddekit_slab * slab) +{ + void *ret = NULL; + l4lock_lock(&slab->lock); + ret = l4slab_alloc(&slab->cache); + l4lock_unlock(&slab->lock); + + return ret; +} + + +/** + * Free object in slab + */ +void ddekit_slab_free(struct ddekit_slab * slab, void *objp) +{ + l4lock_lock(&slab->lock); + l4slab_free(&slab->cache, objp); + l4lock_unlock(&slab->lock); +} + + +/** + * Store user pointer in slab cache + */ +void ddekit_slab_set_data(struct ddekit_slab * slab, void *data) +{ + l4slab_set_data(&slab->cache, data); +} + + +/** + * Read user pointer from slab cache + */ +void *ddekit_slab_get_data(struct ddekit_slab * slab) +{ + return l4slab_get_data(&slab->cache); +} + + +/** + * Destroy slab cache + * + * \param slab pointer to slab cache structure + */ +void ddekit_slab_destroy (struct ddekit_slab * slab) +{ + l4slab_destroy(&slab->cache); + ddekit_simple_free(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) +{ + struct ddekit_slab * slab; + int err; + + slab = (struct ddekit_slab *) ddekit_simple_malloc(sizeof(*slab)); + slab->lock = L4LOCK_UNLOCKED; + err = l4slab_cache_init(&slab->cache, size, 0, _slab_grow, _slab_shrink); + if (err) { + ddekit_debug("error initializing cache"); + ddekit_simple_free(slab); + return 0; + } + + slab->contiguous = contiguous; + + return slab; +} + + +/********************************** + ** Large block memory allocator ** + **********************************/ + +/** + * Free large block of memory + * + * This is no useful for allocation < page size. + */ +void ddekit_large_free(void *objp) +{ + /* clear PTEs */ + ddekit_pgtab_clear_region(objp, PTE_TYPE_LARGE); + + /* release */ + l4dm_mem_release(objp); +} + + +/** + * Allocate large block of memory + * + * This is no useful for allocation < page size. + */ +void *ddekit_large_malloc(int size) +{ + void *res; + int err; + l4_size_t tmp; + int pages; + 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, + "ddekit mem"); + if (! res) + return NULL; + + err = l4dm_mem_phys_addr(res, 1, &dm_paddr, 1, &tmp); + if (err != 1) + ddekit_debug("ddekit_large_malloc: error getting physical address of new memory!\n"); + + ddekit_pgtab_set_region(res, dm_paddr.addr, pages, PTE_TYPE_LARGE); + + return res; +} + + +/** + * 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..24ace989 --- /dev/null +++ b/libddekit/panic.c @@ -0,0 +1,29 @@ +#include <l4/dde/ddekit/panic.h> +#include <l4/dde/ddekit/printf.h> + +#include <l4/sys/kdebug.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"); + + while (1) + enter_kdebug("ddekit_panic()"); +} + +void ddekit_debug(char *fmt, ...) { + va_list va; + + va_start(va, fmt); + ddekit_vprintf(fmt, va); + va_end(va); + ddekit_printf("\n"); + + enter_kdebug("ddekit_debug()"); +} + diff --git a/libddekit/pci.c b/libddekit/pci.c new file mode 100644 index 00000000..35fb7aea --- /dev/null +++ b/libddekit/pci.c @@ -0,0 +1,392 @@ +#include <l4/dde/ddekit/pci.h> +#include <l4/dde/ddekit/printf.h> +#include <l4/dde/ddekit/panic.h> +#include <l4/dde/ddekit/memory.h> +#include <l4/dde/ddekit/assert.h> + +#include <l4/generic_io/types.h> +#include <l4/generic_io/libio.h> +#include <l4/env/errno.h> +#include <l4/log/l4log.h> + +#include "config.h" + +#define dbg_this 0 + +#define MAX_PCI_DEVS 32 + +/** PCI descriptor */ +typedef struct ddekit_pci_dev { + int bus; /**< bus ID */ + int slot; /**< slot ID */ + int func; /**< function */ + l4io_pci_dev_t l4dev; /**< L4IO handle */ + struct ddekit_pci_dev *next; /**< chaining info */ +} ddekit_pci_dev_t; + +static ddekit_pci_dev_t ddekit_pci_bus[MAX_PCI_DEVS]; + +static inline int invalid_device(ddekit_pci_dev_t *d) +{ + return d->slot == -1; +} + + +/** Initialize DDEKit PCI module. + * + * \ingroup DDEKit_pci + * + * This function builds a list of devices by querying L4IO. + */ +void ddekit_pci_init(void) +{ + l4io_pdev_t start = 0; + + int slots_found = 0; + int i; + + /* Init device list */ + for (i = 0; i < MAX_PCI_DEVS; i++) + ddekit_pci_bus[i].slot = -1; + + while (1) { + l4io_pci_dev_t l4dev; + int err; + + /* search next device */ + err = l4io_pci_find_device(~0, ~0, start, &l4dev); + if (err) { + if (err == -L4_ENOTFOUND) { + LOGd(dbg_this, "no more pci devices"); + } else { + LOGd(dbg_this, "error: scanning pci devices: %s (%d)", l4env_errstr(err), err); + } + break; + } + + /* next search start from here */ + start = l4dev.handle; + + /* print info */ + + /* Pretend all our devices are chained to exactly one bus. */ + ddekit_pci_bus[slots_found].bus = 0; /*l4dev.bus;*/ + ddekit_pci_bus[slots_found].slot = slots_found; + ddekit_pci_bus[slots_found].func = 0; + ddekit_pci_bus[slots_found].l4dev = l4dev; + + LOGd(dbg_this, "pcib_identify: found device (%x, %x, %x), mapped to (%x, %x, %x)", + l4dev.bus, l4dev.devfn >> 3, l4dev.devfn & 0x07, + ddekit_pci_bus[slots_found].bus, + ddekit_pci_bus[slots_found].slot, + ddekit_pci_bus[slots_found].func); + + ++slots_found; + } +} + + +/** + * 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; + + LOGd(dbg_this, "searching for dev #%d", nr); + + if (nr >= 0 && nr < MAX_PCI_DEVS && !invalid_device(&ddekit_pci_bus[nr])) { + dev = &ddekit_pci_bus[nr]; + *bus = dev->bus; + *slot = dev->slot; + *func = 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); + + LOGd(dbg_this, "start %p (slot %d)", start, start ? start->slot : -1); + int idx = start ? start->slot + 1 : 0; + + for ( ; idx < MAX_PCI_DEVS; ++idx) { + ddekit_pci_dev_t *dev = &ddekit_pci_bus[idx]; + if (!invalid_device(dev) && + (*bus == DDEKIT_PCI_ANY_ID || dev->bus == *bus) && + (*slot == DDEKIT_PCI_ANY_ID || dev->slot == *slot) && + (*func == DDEKIT_PCI_ANY_ID || dev->func == *func)) { + *bus = dev->bus; + *slot = dev->slot; + *func = 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) +{ + return &ddekit_pci_bus[slot]; +} + + +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 l4io_pci_readb_cfg(dev->l4dev.handle, pos, val); + 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 l4io_pci_readw_cfg(dev->l4dev.handle, pos, val); + 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) + return l4io_pci_readl_cfg(dev->l4dev.handle, pos, val); + 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 l4io_pci_writeb_cfg(dev->l4dev.handle, pos, val); + 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 l4io_pci_writew_cfg(dev->l4dev.handle, pos, val); + 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 l4io_pci_writel_cfg(dev->l4dev.handle, pos, val); + else + return -1; +} + +int ddekit_pci_enable_device(struct ddekit_pci_dev *dev) +{ + return l4io_pci_enable(dev->l4dev.handle); +} + +int ddekit_pci_disable_device(struct ddekit_pci_dev *dev) +{ + return l4io_pci_disable(dev->l4dev.handle); +} + +/******************************************************************************** + ** 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->l4dev.vendor; +} + + +/** + * Get PCI device ID. + * + * \param dev device + * + * \ingroup DDEKit_pci + */ +unsigned short ddekit_pci_get_device_id(struct ddekit_pci_dev *dev) +{ + return dev->l4dev.device; +} + + +/** + * 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->l4dev.sub_vendor; +} + + +/** + * 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->l4dev.sub_device; +} + + +/** + * Get PCI device class ID. + * + * \param dev device + * + * \ingroup DDEKit_pci + */ +unsigned ddekit_pci_get_dev_class(struct ddekit_pci_dev *dev) +{ + return dev->l4dev.dev_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->l4dev.irq; +} + + +/** + * Get PCI device name. + * + * \param dev device + * + * \ingroup DDEKit_pci + */ +char *ddekit_pci_get_name(struct ddekit_pci_dev *dev) +{ + return dev->l4dev.name; +} + + +/** + * Get PCI device slot name. + * + * \param dev device + * + * \ingroup DDEKit_pci + */ +char *ddekit_pci_get_slot_name(struct ddekit_pci_dev *dev) +{ + return dev->l4dev.slot_name; +} + + +/** + * 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) +{ + 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) +{ + 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-old.c b/libddekit/pgtab-old.c new file mode 100644 index 00000000..2b13698a --- /dev/null +++ b/libddekit/pgtab-old.c @@ -0,0 +1,219 @@ +/* + * \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 + * + * Implementation of page tables for saving virt->phys assignments. + * + * FIXME: This works for 32-bit architectures only! (Mostly because of pgtab.h.) + */ + +#include <l4/dde/ddekit/pgtab.h> + +#include <l4/sys/l4int.h> +#include <l4/sys/consts.h> +#include <l4/util/macros.h> +#include <l4/dm_mem/dm_mem.h> +#include <l4/log/l4log.h> + + +/********************************** + ** Page-table utility functions ** + **********************************/ + +/* some useful consts */ +enum +{ + PDIR_SHIFT = L4_SUPERPAGESHIFT, /* readable alias */ + PDIR_MASK = L4_SUPERPAGEMASK, /* readable alias */ + PDIR_ENTRIES = (1 << (L4_MWORD_BITS - PDIR_SHIFT)), + PTAB_ENTRIES = (1 << (PDIR_SHIFT - L4_PAGESHIFT)), + PTAB_SIZE = (sizeof(void*) * PTAB_ENTRIES) +}; + +/** + * Page table entry. + * bit 00-01: type, 0->largemalloc 1->slab page 2->contigmalloc (PTE_TYPE_*) + * bit 02-11: size in number of pages + * bit 12-31: physical page address + */ +typedef union +{ + unsigned compact; + struct + { + unsigned type : 2; + unsigned pages : 10; + unsigned phys : 20; + } components; +} ddekit_pte; + +/** + * Calculate offset of address in page directory - page-table number + */ +static inline unsigned pt_num(l4_addr_t addr) { + return addr >> PDIR_SHIFT; } + + +/** + * Calculate offset of address in page table - page number + */ +static inline unsigned pg_num(l4_addr_t addr) { + return (addr & ~PDIR_MASK) >> L4_PAGESHIFT; } + + +/* page directory */ +static ddekit_pte *page_dir[PDIR_ENTRIES]; + + +/** + * Get page-table entry + */ +static inline ddekit_pte ddekit_get_pte(void *p) +{ + l4_addr_t addr = (l4_mword_t)p; + ddekit_pte *tab; + + tab = page_dir[pt_num(addr)]; + if (!tab) return (ddekit_pte) 0U; + + return tab[pg_num(addr)]; +} + + +/** + * Set page-table entry + */ +static inline void ddekit_set_pte(void *p, ddekit_pte pte) +{ + l4_addr_t addr = (l4_addr_t) p; + ddekit_pte *tab; + + tab = page_dir[pt_num(addr)]; + if (!tab) { + /* create new page table */ + tab = (ddekit_pte *) + l4dm_mem_allocate_named(PTAB_SIZE, L4DM_CONTIGUOUS|L4DM_PINNED|L4RM_MAP, + "ddekit ptab"); + Assert(tab); + + memset(tab, 0, PTAB_SIZE); + page_dir[pt_num(addr)] = tab; + + if (1) { + l4_addr_t a = l4_trunc_superpage(addr); + LOG("created page table for range [0x%08lx,0x%08lx) @ %p\n", + a, a + L4_SUPERPAGESIZE, tab); + } + + } + + tab[pg_num(addr)] = pte; +} + + +/***************************** + ** Page-table facility API ** + *****************************/ + +/** + * 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 pte type for region + */ +void ddekit_pte_set_region(void *virtual, ddekit_addr_t physical, int pages, int type) +{ + ddekit_pte new; + +#ifdef INVARIANTS + ddekit_pte pte; + /* assert pte not set yet */ + pte = ddekit_get_pte(virtual); + LOGd(pte.compact, "first pte already set! pte=0x%04x", pte.compact); +#endif + + /* build pte */ + new.components.type = type; + new.components.pages = pages; + new.components.phys = physical >> L4_PAGESHIFT; + + /* set first pte */ + ddekit_set_pte(virtual, new); + + /* continuation pte-s don't have pages set */ + new.components.pages = 0; + + /* set continuation pte-s */ + for (pages--; pages; pages--) { + /* prepare continuation pte */ + virtual += L4_PAGESIZE; + new.components.phys++; + +#ifdef INVARIANTS + /* assert pte not set yet */ + pte = ddekit_get_pte(virtual); + LOGd(pte.compact, "continuation pte already set! pte=0x%04x", pte.compact); +#endif + + /* set continuation pte */ + ddekit_set_pte(virtual, new); + } +} + + +/** + * Clear virtual->physical mapping for VM region + * + * \param virtual virtual start address for region + * \param type pte type for region + * + * XXX unused page-tables not free'd + */ +void ddekit_pte_clear_region(void *virtual, int type) +{ + ddekit_pte pte; + int pages = 0; + pte = ddekit_get_pte(virtual); + /* get number of pages from pte */ + pages = pte.components.pages; + /* assert pages != 0 */ + if (pages==0) { + LOG("continuation pte found at base"); + return; + } + /* assert pte set and of correct type */ +#ifdef INVARIANTS + LOGd(! pte.compact, "pte is already clear"); + LOGd(pte.components.type!=type, "pte of wrong type"); +#endif + /* clear first pte */ + ddekit_set_pte(virtual, (ddekit_pte) 0U); + /* clear continuation pte-s */ + for (pages--; pages; pages--) { + virtual += L4_PAGESIZE; + +#ifdef INVARIANTS + /* assert pte set and of correct type */ + pte = ddekit_get_pte(virtual); + if (! pte.compact) { + LOG("pte is already clear"); + break; + } + if (pte.components.type!=type) { + LOG("pte of wrong type"); + break; + } + if (pte.components.pages) { + LOG("unexpected non-continuation pte found"); + break; + } +#endif + + ddekit_set_pte(virtual, (ddekit_pte) 0U); + } +} + diff --git a/libddekit/pgtab.c b/libddekit/pgtab.c new file mode 100644 index 00000000..3c39f54f --- /dev/null +++ b/libddekit/pgtab.c @@ -0,0 +1,219 @@ +/* + * \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 <l4/dde/ddekit/pgtab.h> +#include <l4/dde/ddekit/memory.h> +#include <l4/dde/ddekit/panic.h> + +#include <l4/l4rm/l4rm.h> +#include <l4/lock/lock.h> +#include <l4/util/macros.h> + +#include "config.h" + + +/** + * "Page-table" object + */ +struct pgtab_object +{ + l4_addr_t va; /* virtual start address */ + l4_addr_t pa; /* physical start address */ + + /* FIXME reconsider the following members */ + l4_size_t size; + unsigned type; /* pgtab region type */ + + struct pgtab_object * next; + struct pgtab_object * prev; +}; + +/** + * pa_list_head of page-table object list (for get_virtaddr()) + */ +static struct pgtab_object pa_list_head = + { + .va = 0, + .pa = 0, + .size = 0, + .next = &pa_list_head, + .prev = &pa_list_head + }; + +static l4lock_t pa_list_lock = L4LOCK_UNLOCKED; + +/***************************** + ** Page-table facility API ** + *****************************/ + +/** + * 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) +{ + /* find pgtab object */ + struct pgtab_object *p = l4rm_get_userptr(virtual); + if (!p) { + /* XXX this is verbose */ + LOG_Error("no virt->phys mapping for virtual address %p", virtual); + return 0; + } + + /* return virt->phys mapping */ + l4_size_t offset = (l4_addr_t) virtual - p->va; + + return p->pa + offset; +} + +/** + * 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) +{ + /* find pgtab object */ + struct pgtab_object *p; + ddekit_addr_t retval = 0; + + /* find phys->virt mapping */ + l4lock_lock(&pa_list_lock); + for (p = pa_list_head.next ; p != &pa_list_head ; p = p->next) { + if (p->pa <= (l4_addr_t)physical && + (l4_addr_t)physical < p->pa + p->size) { + l4_size_t offset = (l4_addr_t) physical - p->pa; + retval = p->va + offset; + break; + } + } + l4lock_unlock(&pa_list_lock); + + if (!retval) + LOG_Error("no phys->virt mapping for physical address %p", (void*)physical); + + return retval; +} + + + +int ddekit_pgtab_get_type(const void *virtual) +{ + /* 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; +} + + +int ddekit_pgtab_get_size(const void *virtual) +{ + /* 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->size; +} + + +/** + * 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 pgtab_object *p; + + /* find pgtab object */ + p = (struct pgtab_object *)l4rm_get_userptr(virtual); + if (!p) { + /* XXX this is verbose */ + LOG_Error("no virt->phys mapping for %p", virtual); + return; + } + + /* reset userptr in region map */ + /* XXX no error handling here */ + l4rm_set_userptr(virtual, 0); + + /* remove pgtab object from list */ + l4lock_lock(&pa_list_lock); + p->next->prev= p->prev; + p->prev->next= p->next; + l4lock_unlock(&pa_list_lock); + + /* free pgtab object */ + ddekit_simple_free(p); +} + + +/** + * 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) +{ + /* allocate pgtab object */ + struct pgtab_object *p = ddekit_simple_malloc(sizeof(*p)); + if (!p) { + LOG_Error("ddekit heap exhausted"); + return; + } + + /* initialize pgtab object */ + p->va = l4_trunc_page(virtual); + p->pa = l4_trunc_page(physical); + p->size = pages * L4_PAGESIZE; + p->type = type; + + l4lock_lock(&pa_list_lock); + p->next=pa_list_head.next; + p->prev=&pa_list_head; + pa_list_head.next->prev=p; + pa_list_head.next=p; + l4lock_unlock(&pa_list_lock); + + /* set userptr in region map to pgtab object */ + int err = l4rm_set_userptr((void *)p->va, p); + if (err) { + LOG_Error("l4rm_set_userptr returned %d", err); + ddekit_panic("l4rm_set_userptr"); + ddekit_simple_free(p); + } +} + +void ddekit_pgtab_set_region_with_size(void *virt, ddekit_addr_t phys, int size, int type) +{ + int p = l4_round_page(size); + p >>= L4_PAGESHIFT; + ddekit_pgtab_set_region(virt, phys, p, type); +} + diff --git a/libddekit/printf.c b/libddekit/printf.c new file mode 100644 index 00000000..fb13a0b4 --- /dev/null +++ b/libddekit/printf.c @@ -0,0 +1,46 @@ +/* + * \brief Logging facility with printf()-like interface + * \author Thomas Friebel <yaron@yaron.de> + * \date 2006-03-01 + */ + +#include <l4/dde/ddekit/printf.h> + +#include <l4/log/l4log.h> + +/** + * Log constant string message w/o arguments + * + * \param msg message to be logged + */ +int ddekit_print(const char *msg) +{ + return LOG_printf("%s", msg); +} + +/** + * 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) +{ + return LOG_vprintf(fmt, va); +} diff --git a/libddekit/resources.c b/libddekit/resources.c new file mode 100644 index 00000000..d4d421c4 --- /dev/null +++ b/libddekit/resources.c @@ -0,0 +1,57 @@ +#include <l4/dde/ddekit/resources.h> + +#include <l4/generic_io/libio.h> + +#include "config.h" + +int ddekit_request_dma(int nr) { + return l4io_request_dma(nr); +} + +int ddekit_release_dma(int nr) { + return l4io_release_dma(nr); +} + +/** Request an IO region + * + * \return 0 success + * \return -1 error + */ +int ddekit_request_io(ddekit_addr_t start, ddekit_addr_t count) { + return l4io_request_region(start, count); +} + +/** Release an IO region. + * + * \return 0 success + * \return <0 error + */ +int ddekit_release_io(ddekit_addr_t start, ddekit_addr_t count) { + return l4io_release_region(start, count); +} + +/** 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) { + ddekit_addr_t v; + + v = l4io_request_mem_region(start, count, 0); + if (v) { + *vaddr = v; + return 0; + } else + return -1; +} + +/** Release memory region. + * + * \return 0 success + * \return <0 error + */ +int ddekit_release_mem(ddekit_addr_t start, ddekit_addr_t count) { + return l4io_release_mem_region(start, count); +} diff --git a/libddekit/semaphore.c b/libddekit/semaphore.c new file mode 100644 index 00000000..6fbb7f35 --- /dev/null +++ b/libddekit/semaphore.c @@ -0,0 +1,48 @@ +#include <l4/dde/ddekit/semaphore.h> +#include <l4/dde/ddekit/memory.h> + +#include <l4/semaphore/semaphore.h> + +struct ddekit_sem { + l4semaphore_t sem; +}; + +ddekit_sem_t *ddekit_sem_init(int value) { + ddekit_sem_t *sem; + + sem = (ddekit_sem_t *) ddekit_simple_malloc(sizeof(*sem)); + sem->sem = L4SEMAPHORE_INIT(value); + + return sem; +} + +void ddekit_sem_deinit(ddekit_sem_t *sem) { + ddekit_simple_free(sem); +} + +void ddekit_sem_down(ddekit_sem_t *sem) { +#if 0 + printf("%s:%d sem=%p l4sem=0x%08x\n", __FILE__, __LINE__, sem, sem->sem); + enter_kdebug(""); +#endif + l4semaphore_down(&sem->sem); +/*printf("%s:%d\n", __FILE__, __LINE__); */ +} + +/* returns 0 on success, != 0 when it would block */ +int ddekit_sem_down_try(ddekit_sem_t *sem) { + return l4semaphore_try_down(&sem->sem) ? 0 : 1; +} + +/* returns 0 on success, != 0 on timeout */ +int ddekit_sem_down_timed(ddekit_sem_t *sem, int timo) { + return l4semaphore_down_timed(&sem->sem, timo); +} + +void ddekit_sem_up(ddekit_sem_t *sem) { +#if 0 + printf("%s:%d sem=%p l4sem=0x%08x\n", __FILE__, __LINE__, sem, sem->sem); +#endif + l4semaphore_up(&sem->sem); +} + diff --git a/libddekit/thread.c b/libddekit/thread.c new file mode 100644 index 00000000..db767dc9 --- /dev/null +++ b/libddekit/thread.c @@ -0,0 +1,195 @@ +#include <l4/dde/ddekit/thread.h> +#include <l4/dde/ddekit/condvar.h> +#include <l4/dde/ddekit/panic.h> +#include <l4/dde/ddekit/memory.h> +#include <l4/dde/ddekit/printf.h> + +#include <l4/dde/dde.h> +#include <l4/thread/thread.h> +#include <l4/log/l4log.h> +#include <l4/sys/syscalls.h> +#include <l4/util/rdtsc.h> + +#include <stdio.h> +#include <string.h> + +#define DDEKIT_THREAD_STACK_SIZE 0x2000 /* 8 KB */ + +static struct ddekit_slab *ddekit_stack_slab = NULL; + +struct ddekit_thread { + l4thread_t l4thread; + void *data; + void *stack; + ddekit_condvar_t *sleep_cv; + const char *name; +}; + +/** + * The thread-local-storage key for the BSD struct thread. + */ +static int tlskey_thread; + +struct startup_args { + void (*fun)(void *); + void *arg; + const char *name; +}; + +ddekit_thread_t *ddekit_thread_setup_myself(const char *name) { + ddekit_thread_t *td; + int namelen = strlen(name); + char *pname; + + td = ddekit_simple_malloc(sizeof(*td) + (namelen+1)); + pname = (char *) td + sizeof(*td); + + td->data=NULL; + td->sleep_cv = ddekit_condvar_init(); + td->l4thread = l4thread_myself(); + td->name = pname; + + strcpy(pname, name); + + l4thread_data_set_current(tlskey_thread, td); + + return td; +} + +static void ddekit_thread_startup(void *arg) { + struct startup_args su; + ddekit_thread_t *td; + + /* copy arg to su so that it can bee freed by caller */ + su = *((struct startup_args*)arg); + + /* init dde thread structure */ + td = ddekit_thread_setup_myself(su.name); + /* inform caller of initialization */ + l4thread_started(td); + + /* call thread routine */ + su.fun(su.arg); +} + +ddekit_thread_t *ddekit_thread_create(void (*fun)(void *), void *arg, const char *name) { + struct startup_args su; + ddekit_thread_t *td; + l4thread_t l4td; + char l4name[20]; + void *stack; + + su.fun = fun; + su.arg = arg; + su.name = name; + + snprintf(l4name, 20, ".%s", name); + + stack = ddekit_slab_alloc(ddekit_stack_slab); + + + l4td = l4thread_create_long(L4THREAD_INVALID_ID, ddekit_thread_startup, l4name, + (l4_addr_t) stack + (DDEKIT_THREAD_STACK_SIZE-1 )* sizeof (void *), + DDEKIT_THREAD_STACK_SIZE, + L4THREAD_DEFAULT_PRIO, &su, L4THREAD_CREATE_SYNC); + + if (l4td < 0) + ddekit_panic("error creating thread"); + + td = (ddekit_thread_t*) l4thread_startup_return(l4td); + + td->stack = stack; + + return td; +} + +ddekit_thread_t *ddekit_thread_myself(void) { + return (ddekit_thread_t *) l4thread_data_get_current(tlskey_thread); +} + +void ddekit_thread_set_data(ddekit_thread_t *thread, void *data) { + thread->data = 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->data; +} + +void *ddekit_thread_get_my_data() { + return ddekit_thread_get_data(ddekit_thread_myself()); +} + +void ddekit_thread_msleep(unsigned long msecs) { + l4thread_sleep(msecs); +} + +void ddekit_thread_usleep(unsigned long usecs) { + l4_busy_wait_us(usecs); +} + + +void ddekit_thread_nsleep(unsigned long nsecs) { + l4_busy_wait_ns(nsecs); +} + +void ddekit_thread_sleep(ddekit_lock_t *lock) { + ddekit_thread_t *td; + + td = ddekit_thread_myself(); + + ddekit_condvar_wait(td->sleep_cv, lock); +} + +void ddekit_thread_wakeup(ddekit_thread_t *td) { + ddekit_condvar_signal(td->sleep_cv); +} + +void ddekit_thread_exit() { + ddekit_thread_t *td; + + td = ddekit_thread_myself(); + + l4thread_exit(); + + ddekit_slab_free(ddekit_stack_slab ,td->stack); + +} + +void ddekit_thread_terminate(ddekit_thread_t *t) +{ + l4thread_shutdown(t->l4thread); +} + +const char *ddekit_thread_get_name(ddekit_thread_t *thread) { + return thread->name; +} + +int ddekit_thread_get_id(ddekit_thread_t *t) +{ + return t->l4thread; +} + +void ddekit_thread_schedule(void) +{ + l4_yield(); +} + +void ddekit_yield(void) +{ + l4_yield(); +} + +void ddekit_init_threads() { + /* register TLS key for pointer to dde thread structure */ + tlskey_thread = l4thread_data_allocate_key(); + + /* setup dde part of thread data */ + ddekit_thread_setup_myself("main"); + + /* create slab for stacks */ + ddekit_stack_slab = ddekit_slab_init(DDEKIT_THREAD_STACK_SIZE, 1); +} diff --git a/libddekit/timer.c b/libddekit/timer.c new file mode 100644 index 00000000..b1af99bf --- /dev/null +++ b/libddekit/timer.c @@ -0,0 +1,329 @@ +#include <l4/dde/ddekit/timer.h> +#include <l4/dde/ddekit/thread.h> +#include <l4/dde/ddekit/printf.h> +#include <l4/dde/ddekit/panic.h> +#include <l4/dde/ddekit/assert.h> +#include <l4/dde/ddekit/memory.h> +#include <l4/dde/ddekit/semaphore.h> + +#include <l4/thread/thread.h> +#include <l4/lock/lock.h> +#include <l4/env/errno.h> +#include <l4/generic_io/libio.h> +#include <l4/sys/ipc.h> +#include <l4/util/rdtsc.h> + +#define __DEBUG 0 + +/* 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. + */ +extern volatile unsigned long jiffies; +extern unsigned long 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 l4lock_t timer_lock = L4LOCK_UNLOCKED; ///< lock to access timer_list +static l4_threadid_t timer_thread = L4_NIL_ID; ///< the timer thread +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 +} + + +/** Notify the timer thread there is a new timer at the beginning of the + * timer list. + */ +static inline void __notify_timer_thread(void) +{ + int err; + l4_msgdope_t result; + + /* 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 (l4_is_nil_id(timer_thread)) + 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; + + l4lock_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(!l4_is_nil_id(timer_thread)); + __notify_timer_thread(); + } + + l4lock_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; + + l4lock_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: + l4lock_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; + + l4lock_lock(&timer_lock); + + t = timer_list; + while (t) { + if (t->id == timer) { + r = 1; + break; + } + t = t->next; + } + + l4lock_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(l4_thread_equal(l4thread_l4_id(l4lock_owner(&timer_lock)), + timer_thread)); + + 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) +{ + l4_umword_t dummy; + l4_msgdope_t res; + + int err = 0; + + l4lock_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 + } + + l4lock_lock(&timer_lock); + + return (err ? 1 : 0); +} + + +static void ddekit_timer_thread(void *arg) +{ + timer_thread_ddekit = ddekit_thread_setup_myself("ddekit_timer"); + + notify_semaphore = ddekit_sem_init(0); +#if 0 + l4thread_set_prio(l4thread_myself(), 0x11); +#endif + + l4thread_started(0); + + l4lock_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) { + l4lock_unlock(&timer_lock); + //ddekit_printf("doing timer fn @ %p\n", timer->fn); + timer->fn(timer->args); + ddekit_simple_free(timer); + l4lock_lock(&timer_lock); + } + } +} + +ddekit_thread_t *ddekit_get_timer_thread() +{ + return timer_thread_ddekit; +} + + +void ddekit_init_timers(void) +{ + l4_tsc_init(L4_TSC_INIT_AUTO); + + /* XXX this module needs HZ and jiffies to work - so l4io info page must be mapped */ + timer_thread = l4thread_l4_id( l4thread_create_named(ddekit_timer_thread, + "ddekit_timer", 0, + L4THREAD_CREATE_SYNC)); +} |