From a3eba19470c09f42272dac5ca1a34bd8a5cbe834 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 17 Nov 2009 10:26:25 +0100 Subject: The original version of DDEKit. --- libddekit/Makefile | 9 + libddekit/condvar.c | 108 ++++++++++++ libddekit/config.h | 13 ++ libddekit/init.c | 35 ++++ libddekit/initcall.c | 8 + libddekit/interrupt.c | 229 +++++++++++++++++++++++++ libddekit/lock.c | 62 +++++++ libddekit/malloc.c | 94 ++++++++++ libddekit/memory.c | 467 ++++++++++++++++++++++++++++++++++++++++++++++++++ libddekit/panic.c | 29 ++++ libddekit/pci.c | 392 ++++++++++++++++++++++++++++++++++++++++++ libddekit/pgtab-old.c | 219 +++++++++++++++++++++++ libddekit/pgtab.c | 219 +++++++++++++++++++++++ libddekit/printf.c | 46 +++++ libddekit/resources.c | 57 ++++++ libddekit/semaphore.c | 48 ++++++ libddekit/thread.c | 195 +++++++++++++++++++++ libddekit/timer.c | 329 +++++++++++++++++++++++++++++++++++ 18 files changed, 2559 insertions(+) create mode 100644 libddekit/Makefile create mode 100644 libddekit/condvar.c create mode 100644 libddekit/config.h create mode 100644 libddekit/init.c create mode 100644 libddekit/initcall.c create mode 100644 libddekit/interrupt.c create mode 100644 libddekit/lock.c create mode 100644 libddekit/malloc.c create mode 100644 libddekit/memory.c create mode 100644 libddekit/panic.c create mode 100644 libddekit/pci.c create mode 100644 libddekit/pgtab-old.c create mode 100644 libddekit/pgtab.c create mode 100644 libddekit/printf.c create mode 100644 libddekit/resources.c create mode 100644 libddekit/semaphore.c create mode 100644 libddekit/thread.c create mode 100644 libddekit/timer.c (limited to 'libddekit') 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 + */ +#include +#include +#include + +#include +#include +#include + +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; isem); + } + l4lock_unlock(&cvp->lock); + for (i=0; ihandshake); + } + } 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 + */ +#include +#include +#include + +#include +#include +#include +#include + +/* 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 + +#include + +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 + * \author Christian Helmuth + * \date 2007-01-22 + * + * FIXME could intloop_param freed after startup? + * FIXME use consume flag to indicate IRQ was handled + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#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 +#include + +#include +#include + +#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 +#include +#include + +#include +#include +#include +#include + +/* 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 + * \author Christian Helmuth + * \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 +#include +#include +#include + +#include +#include +#include +#include +#include + + +/**************** + ** 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 +#include + +#include +#include + +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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 + * \author Christian Helmuth + * \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 + +#include +#include +#include +#include +#include + + +/********************************** + ** 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 + * \author Christian Helmuth + * \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 +#include +#include + +#include +#include +#include + +#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 + * \date 2006-03-01 + */ + +#include + +#include + +/** + * 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 + +#include + +#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 +#include + +#include + +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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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)); +} -- cgit v1.2.3 From 9290f1fe99c91ba6c57dec956ff73d1741d81b45 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 17 Nov 2009 10:29:23 +0100 Subject: Add DDEKit headers. --- libddekit/include/.svn/all-wcprops | 17 + libddekit/include/.svn/entries | 99 ++++ libddekit/include/.svn/format | 1 + libddekit/include/.svn/text-base/Makefile.svn-base | 9 + libddekit/include/.svn/text-base/dde.h.svn-base | 14 + libddekit/include/Makefile | 9 + libddekit/include/dde.h | 14 + libddekit/include/ddekit/.svn/all-wcprops | 107 ++++ libddekit/include/ddekit/.svn/entries | 606 +++++++++++++++++++++ libddekit/include/ddekit/.svn/format | 1 + .../ddekit/.svn/text-base/assert.h.svn-base | 23 + .../ddekit/.svn/text-base/condvar.h.svn-base | 54 ++ .../include/ddekit/.svn/text-base/debug.h.svn-base | 8 + .../ddekit/.svn/text-base/initcall.h.svn-base | 42 ++ .../ddekit/.svn/text-base/inline.h.svn-base | 2 + .../ddekit/.svn/text-base/interrupt.h.svn-base | 57 ++ .../include/ddekit/.svn/text-base/lock.h.svn-base | 83 +++ .../ddekit/.svn/text-base/memory.h.svn-base | 144 +++++ .../include/ddekit/.svn/text-base/panic.h.svn-base | 16 + .../include/ddekit/.svn/text-base/pci.h.svn-base | 199 +++++++ .../include/ddekit/.svn/text-base/pgtab.h.svn-base | 86 +++ .../ddekit/.svn/text-base/printf.h.svn-base | 33 ++ .../ddekit/.svn/text-base/resources.h.svn-base | 13 + .../ddekit/.svn/text-base/semaphore.h.svn-base | 50 ++ .../ddekit/.svn/text-base/thread.h.svn-base | 162 ++++++ .../include/ddekit/.svn/text-base/timer.h.svn-base | 55 ++ .../include/ddekit/.svn/text-base/types.h.svn-base | 22 + libddekit/include/ddekit/assert.h | 23 + libddekit/include/ddekit/condvar.h | 54 ++ libddekit/include/ddekit/debug.h | 8 + libddekit/include/ddekit/initcall.h | 42 ++ libddekit/include/ddekit/inline.h | 2 + libddekit/include/ddekit/interrupt.h | 57 ++ libddekit/include/ddekit/lock.h | 83 +++ libddekit/include/ddekit/memory.h | 144 +++++ libddekit/include/ddekit/panic.h | 16 + libddekit/include/ddekit/pci.h | 199 +++++++ libddekit/include/ddekit/pgtab.h | 86 +++ libddekit/include/ddekit/printf.h | 33 ++ libddekit/include/ddekit/resources.h | 13 + libddekit/include/ddekit/semaphore.h | 50 ++ libddekit/include/ddekit/thread.h | 162 ++++++ libddekit/include/ddekit/timer.h | 55 ++ libddekit/include/ddekit/types.h | 22 + 44 files changed, 2975 insertions(+) create mode 100644 libddekit/include/.svn/all-wcprops create mode 100644 libddekit/include/.svn/entries create mode 100644 libddekit/include/.svn/format create mode 100644 libddekit/include/.svn/text-base/Makefile.svn-base create mode 100644 libddekit/include/.svn/text-base/dde.h.svn-base create mode 100644 libddekit/include/Makefile create mode 100644 libddekit/include/dde.h create mode 100644 libddekit/include/ddekit/.svn/all-wcprops create mode 100644 libddekit/include/ddekit/.svn/entries create mode 100644 libddekit/include/ddekit/.svn/format create mode 100644 libddekit/include/ddekit/.svn/text-base/assert.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/condvar.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/debug.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/initcall.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/inline.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/interrupt.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/lock.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/memory.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/panic.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/pci.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/pgtab.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/printf.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/resources.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/semaphore.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/thread.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/timer.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/types.h.svn-base create mode 100644 libddekit/include/ddekit/assert.h create mode 100644 libddekit/include/ddekit/condvar.h create mode 100644 libddekit/include/ddekit/debug.h create mode 100644 libddekit/include/ddekit/initcall.h create mode 100644 libddekit/include/ddekit/inline.h create mode 100644 libddekit/include/ddekit/interrupt.h create mode 100644 libddekit/include/ddekit/lock.h create mode 100644 libddekit/include/ddekit/memory.h create mode 100644 libddekit/include/ddekit/panic.h create mode 100644 libddekit/include/ddekit/pci.h create mode 100644 libddekit/include/ddekit/pgtab.h create mode 100644 libddekit/include/ddekit/printf.h create mode 100644 libddekit/include/ddekit/resources.h create mode 100644 libddekit/include/ddekit/semaphore.h create mode 100644 libddekit/include/ddekit/thread.h create mode 100644 libddekit/include/ddekit/timer.h create mode 100644 libddekit/include/ddekit/types.h (limited to 'libddekit') diff --git a/libddekit/include/.svn/all-wcprops b/libddekit/include/.svn/all-wcprops new file mode 100644 index 00000000..7ba2dd51 --- /dev/null +++ b/libddekit/include/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 50 +/repos/tudos/!svn/ver/457/trunk/l4/pkg/dde/include +END +dde.h +K 25 +svn:wc:ra_dav:version-url +V 56 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/dde.h +END +Makefile +K 25 +svn:wc:ra_dav:version-url +V 59 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/Makefile +END diff --git a/libddekit/include/.svn/entries b/libddekit/include/.svn/entries new file mode 100644 index 00000000..4bc0ab10 --- /dev/null +++ b/libddekit/include/.svn/entries @@ -0,0 +1,99 @@ +9 + +dir +465 +http://svn.tudos.org/repos/tudos/trunk/l4/pkg/dde/include +http://svn.tudos.org/repos/tudos + + + +2009-05-23T02:50:17.774710Z +457 +l4check + + +svn:special svn:externals svn:needs-lock + + + + + + + + + + + +a704ac0b-3a55-4d43-a2a9-7be6f07c34fb + +dde.h +file + + + + +2009-11-15T17:14:44.000000Z +55a0119faab08988da07a2e0aa7f95a9 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +308 + +ddekit +dir + +Makefile +file + + + + +2009-11-15T17:14:44.000000Z +48ec0344857f2fa21c99f765cc91f0e6 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +276 + diff --git a/libddekit/include/.svn/format b/libddekit/include/.svn/format new file mode 100644 index 00000000..ec635144 --- /dev/null +++ b/libddekit/include/.svn/format @@ -0,0 +1 @@ +9 diff --git a/libddekit/include/.svn/text-base/Makefile.svn-base b/libddekit/include/.svn/text-base/Makefile.svn-base new file mode 100644 index 00000000..8d31023f --- /dev/null +++ b/libddekit/include/.svn/text-base/Makefile.svn-base @@ -0,0 +1,9 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +# All haeder files found in this directory tree will be automatically +# installed in a way that they can be included with +# #include later. +# No need to list them in this Makefile. + +include $(L4DIR)/mk/include.mk diff --git a/libddekit/include/.svn/text-base/dde.h.svn-base b/libddekit/include/.svn/text-base/dde.h.svn-base new file mode 100644 index 00000000..12f8a81a --- /dev/null +++ b/libddekit/include/.svn/text-base/dde.h.svn-base @@ -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/include/Makefile b/libddekit/include/Makefile new file mode 100644 index 00000000..8d31023f --- /dev/null +++ b/libddekit/include/Makefile @@ -0,0 +1,9 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +# All haeder files found in this directory tree will be automatically +# installed in a way that they can be included with +# #include later. +# No need to list them in this Makefile. + +include $(L4DIR)/mk/include.mk diff --git a/libddekit/include/dde.h b/libddekit/include/dde.h new file mode 100644 index 00000000..12f8a81a --- /dev/null +++ b/libddekit/include/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/include/ddekit/.svn/all-wcprops b/libddekit/include/ddekit/.svn/all-wcprops new file mode 100644 index 00000000..e216cf47 --- /dev/null +++ b/libddekit/include/ddekit/.svn/all-wcprops @@ -0,0 +1,107 @@ +K 25 +svn:wc:ra_dav:version-url +V 57 +/repos/tudos/!svn/ver/457/trunk/l4/pkg/dde/include/ddekit +END +panic.h +K 25 +svn:wc:ra_dav:version-url +V 65 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/panic.h +END +interrupt.h +K 25 +svn:wc:ra_dav:version-url +V 69 +/repos/tudos/!svn/ver/301/trunk/l4/pkg/dde/include/ddekit/interrupt.h +END +condvar.h +K 25 +svn:wc:ra_dav:version-url +V 67 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/condvar.h +END +pgtab.h +K 25 +svn:wc:ra_dav:version-url +V 65 +/repos/tudos/!svn/ver/395/trunk/l4/pkg/dde/include/ddekit/pgtab.h +END +initcall.h +K 25 +svn:wc:ra_dav:version-url +V 68 +/repos/tudos/!svn/ver/238/trunk/l4/pkg/dde/include/ddekit/initcall.h +END +assert.h +K 25 +svn:wc:ra_dav:version-url +V 66 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/assert.h +END +printf.h +K 25 +svn:wc:ra_dav:version-url +V 66 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/printf.h +END +types.h +K 25 +svn:wc:ra_dav:version-url +V 65 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/types.h +END +thread.h +K 25 +svn:wc:ra_dav:version-url +V 66 +/repos/tudos/!svn/ver/238/trunk/l4/pkg/dde/include/ddekit/thread.h +END +memory.h +K 25 +svn:wc:ra_dav:version-url +V 66 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/memory.h +END +resources.h +K 25 +svn:wc:ra_dav:version-url +V 69 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/resources.h +END +pci.h +K 25 +svn:wc:ra_dav:version-url +V 63 +/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/include/ddekit/pci.h +END +inline.h +K 25 +svn:wc:ra_dav:version-url +V 66 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/inline.h +END +timer.h +K 25 +svn:wc:ra_dav:version-url +V 65 +/repos/tudos/!svn/ver/457/trunk/l4/pkg/dde/include/ddekit/timer.h +END +semaphore.h +K 25 +svn:wc:ra_dav:version-url +V 69 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/semaphore.h +END +debug.h +K 25 +svn:wc:ra_dav:version-url +V 65 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/debug.h +END +lock.h +K 25 +svn:wc:ra_dav:version-url +V 64 +/repos/tudos/!svn/ver/253/trunk/l4/pkg/dde/include/ddekit/lock.h +END diff --git a/libddekit/include/ddekit/.svn/entries b/libddekit/include/ddekit/.svn/entries new file mode 100644 index 00000000..21752264 --- /dev/null +++ b/libddekit/include/ddekit/.svn/entries @@ -0,0 +1,606 @@ +9 + +dir +465 +http://svn.tudos.org/repos/tudos/trunk/l4/pkg/dde/include/ddekit +http://svn.tudos.org/repos/tudos + + + +2009-05-23T02:50:17.774710Z +457 +l4check + + +svn:special svn:externals svn:needs-lock + + + + + + + + + + + +a704ac0b-3a55-4d43-a2a9-7be6f07c34fb + +panic.h +file + + + + +2009-11-15T17:14:44.000000Z +2570239ee2dbc1154cf146aa16bcf547 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +330 + +interrupt.h +file + + + + +2009-11-15T17:14:44.000000Z +ee8b18c79ba7d7cf50a35d8105f68750 +2008-02-16T03:51:13.191963Z +301 +l4check + + + + + + + + + + + + + + + + + + + + + +1586 + +condvar.h +file + + + + +2009-11-15T17:14:44.000000Z +6ad1a17ba32ef17c1345685eda2bb129 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +1239 + +pgtab.h +file + + + + +2009-11-15T17:14:44.000000Z +5991c64662b8e2d95e1202eb4ff6045c +2008-08-14T02:50:25.232552Z +395 +l4check + + + + + + + + + + + + + + + + + + + + + +2086 + +initcall.h +file + + + + +2009-11-15T17:14:44.000000Z +c04d502176e023a054602b5d18ac29e1 +2007-11-08T03:52:28.731143Z +238 +l4check + + + + + + + + + + + + + + + + + + + + + +1135 + +assert.h +file + + + + +2009-11-15T17:14:44.000000Z +ab222d72d5dc9ad29a5c435561818d0c +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +592 + +printf.h +file + + + + +2009-11-15T17:14:44.000000Z +a0e9adfc93ede606218916e4f5d9f437 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +731 + +types.h +file + + + + +2009-11-15T17:14:44.000000Z +a0fd3a957254115d16d6bafe5f23c630 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +616 + +thread.h +file + + + + +2009-11-15T17:14:44.000000Z +1e42c7c3396e9dbb7d238e19e4368e6d +2007-11-08T03:52:28.731143Z +238 +l4check + + + + + + + + + + + + + + + + + + + + + +3877 + +memory.h +file + + + + +2009-11-15T17:14:44.000000Z +980f4cc26bf2735a3518da3d16060500 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +3486 + +resources.h +file + + + + +2009-11-15T17:14:44.000000Z +cdd94bcecf43cb4001bf3f5919704968 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +449 + +pci.h +file + + + + +2009-11-15T17:14:44.000000Z +3d708d2ff3ac2937415cd19bb0ac9e0d +2009-05-20T14:32:55.606606Z +455 +l4check + + + + + + + + + + + + + + + + + + + + + +5045 + +inline.h +file + + + + +2009-11-15T17:14:44.000000Z +0c47197d7519e09e4b8bbd76b56c4b60 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +58 + +timer.h +file + + + + +2009-11-15T17:14:44.000000Z +850acfa4cd49770e7a2f8b511b1cfde4 +2009-05-23T02:50:17.774710Z +457 +l4check + + + + + + + + + + + + + + + + + + + + + +1186 + +semaphore.h +file + + + + +2009-11-15T17:14:44.000000Z +b8f721cb8c9d58ba4d163510c9687843 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +991 + +debug.h +file + + + + +2009-11-15T17:14:44.000000Z +8a52d2548bcf2855c1d843a074e81ceb +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +146 + +lock.h +file + + + + +2009-11-15T17:14:44.000000Z +a8a89bd7ee88b2f8279f2f6716c6ee15 +2007-12-13T03:50:57.801357Z +253 +l4check + + + + + + + + + + + + + + + + + + + + + +2114 + diff --git a/libddekit/include/ddekit/.svn/format b/libddekit/include/ddekit/.svn/format new file mode 100644 index 00000000..ec635144 --- /dev/null +++ b/libddekit/include/ddekit/.svn/format @@ -0,0 +1 @@ +9 diff --git a/libddekit/include/ddekit/.svn/text-base/assert.h.svn-base b/libddekit/include/ddekit/.svn/text-base/assert.h.svn-base new file mode 100644 index 00000000..5d572b49 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/assert.h.svn-base @@ -0,0 +1,23 @@ +#ifndef _ddekit_assert_h +#define _ddekit_assert_h + +#include +#include + +/** \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/include/ddekit/.svn/text-base/condvar.h.svn-base b/libddekit/include/ddekit/.svn/text-base/condvar.h.svn-base new file mode 100644 index 00000000..b6dc4bd3 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/condvar.h.svn-base @@ -0,0 +1,54 @@ +#ifndef _ddekit_condvar_h +#define _ddekit_condvar_h + +/** \file ddekit/condvar.h */ + +#include + +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/include/ddekit/.svn/text-base/debug.h.svn-base b/libddekit/include/ddekit/.svn/text-base/debug.h.svn-base new file mode 100644 index 00000000..79a8e7b5 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/debug.h.svn-base @@ -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/include/ddekit/.svn/text-base/initcall.h.svn-base b/libddekit/include/ddekit/.svn/text-base/initcall.h.svn-base new file mode 100644 index 00000000..b503cc6a --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/initcall.h.svn-base @@ -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) \ + static 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/include/ddekit/.svn/text-base/inline.h.svn-base b/libddekit/include/ddekit/.svn/text-base/inline.h.svn-base new file mode 100644 index 00000000..e59a5c68 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/inline.h.svn-base @@ -0,0 +1,2 @@ +#define INLINE __inline__ __attribute__((always_inline)) + diff --git a/libddekit/include/ddekit/.svn/text-base/interrupt.h.svn-base b/libddekit/include/ddekit/.svn/text-base/interrupt.h.svn-base new file mode 100644 index 00000000..bbabedb2 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/interrupt.h.svn-base @@ -0,0 +1,57 @@ +/* + * \brief Hardware-interrupt subsystem + * \author Thomas Friebel + * \author Christian Helmuth + * \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 + +#define DDEKIT_IRQ_PRIO 0x11 + +/** + * 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/include/ddekit/.svn/text-base/lock.h.svn-base b/libddekit/include/ddekit/.svn/text-base/lock.h.svn-base new file mode 100644 index 00000000..872acad0 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/lock.h.svn-base @@ -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 + +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/include/ddekit/.svn/text-base/memory.h.svn-base b/libddekit/include/ddekit/.svn/text-base/memory.h.svn-base new file mode 100644 index 00000000..051a4d9e --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/memory.h.svn-base @@ -0,0 +1,144 @@ +/* + * \brief Memory subsystem + * \author Thomas Friebel + * \author Christian Helmuth + * \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/include/ddekit/.svn/text-base/panic.h.svn-base b/libddekit/include/ddekit/.svn/text-base/panic.h.svn-base new file mode 100644 index 00000000..1468675f --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/panic.h.svn-base @@ -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/include/ddekit/.svn/text-base/pci.h.svn-base b/libddekit/include/ddekit/.svn/text-base/pci.h.svn-base new file mode 100644 index 00000000..9ec7cd4f --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/pci.h.svn-base @@ -0,0 +1,199 @@ +#ifndef _ddekit_pci_h +#define _ddekit_pci_h + +#include + +/** \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/include/ddekit/.svn/text-base/pgtab.h.svn-base b/libddekit/include/ddekit/.svn/text-base/pgtab.h.svn-base new file mode 100644 index 00000000..3b68192c --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/pgtab.h.svn-base @@ -0,0 +1,86 @@ +/* + * \brief Virtual page-table facility + * \author Thomas Friebel + * \author Christian Helmuth + * \date 2006-11-03 + */ + +#ifndef _ddekit_pgtab_h +#define _ddekit_pgtab_h + +#include + +/* 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/include/ddekit/.svn/text-base/printf.h.svn-base b/libddekit/include/ddekit/.svn/text-base/printf.h.svn-base new file mode 100644 index 00000000..35b0dfa1 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/printf.h.svn-base @@ -0,0 +1,33 @@ +#ifndef _ddekit_print_h +#define _ddekit_print_h + +#include + +/** 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); + +/** 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/include/ddekit/.svn/text-base/resources.h.svn-base b/libddekit/include/ddekit/.svn/text-base/resources.h.svn-base new file mode 100644 index 00000000..e0fa68f0 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/resources.h.svn-base @@ -0,0 +1,13 @@ +#ifndef _ddekit_resources_h +#define _ddekit_resources_h + +#include + +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); + +#endif diff --git a/libddekit/include/ddekit/.svn/text-base/semaphore.h.svn-base b/libddekit/include/ddekit/.svn/text-base/semaphore.h.svn-base new file mode 100644 index 00000000..c959919d --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/semaphore.h.svn-base @@ -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/include/ddekit/.svn/text-base/thread.h.svn-base b/libddekit/include/ddekit/.svn/text-base/thread.h.svn-base new file mode 100644 index 00000000..ecd399d9 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/thread.h.svn-base @@ -0,0 +1,162 @@ +#ifndef _ddekit_thread_h +#define _ddekit_thread_h + +/** \defgroup DDEKit_threads */ + +#include + +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)); + +/** Terminate a thread + * + * \ingroup DDEKit_threads + */ +void ddekit_thread_terminate(ddekit_thread_t *thread); + +/** Get the name, a thread registered with DDEKit. + * + * \ingroup DDEKit_threads + */ +const char *ddekit_thread_get_name(ddekit_thread_t *thread); + +/** Get unique ID of a DDEKit thread. + * + * \ingroup DDEKit_threads + * + * DDEKit does not allow direct access to the thread data + * structure, since this struct contains L4-specific data types. + * However, applications might want to get some kind of ID related + * to a ddekit_thread, for instance to use it as a Linux-like PID. + */ +int ddekit_thread_get_id(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/include/ddekit/.svn/text-base/timer.h.svn-base b/libddekit/include/ddekit/.svn/text-base/timer.h.svn-base new file mode 100644 index 00000000..c352475c --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/timer.h.svn-base @@ -0,0 +1,55 @@ +#ifndef _ddekit_timer_h +#define _ddekit_timer_h + +#include + +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); + +#endif diff --git a/libddekit/include/ddekit/.svn/text-base/types.h.svn-base b/libddekit/include/ddekit/.svn/text-base/types.h.svn-base new file mode 100644 index 00000000..83d92c65 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/types.h.svn-base @@ -0,0 +1,22 @@ +/* + * \brief Types for ddekit (x86 version) + * \author Thomas Friebel + * \author Christian Helmuth + * \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/include/ddekit/assert.h b/libddekit/include/ddekit/assert.h new file mode 100644 index 00000000..5d572b49 --- /dev/null +++ b/libddekit/include/ddekit/assert.h @@ -0,0 +1,23 @@ +#ifndef _ddekit_assert_h +#define _ddekit_assert_h + +#include +#include + +/** \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/include/ddekit/condvar.h b/libddekit/include/ddekit/condvar.h new file mode 100644 index 00000000..b6dc4bd3 --- /dev/null +++ b/libddekit/include/ddekit/condvar.h @@ -0,0 +1,54 @@ +#ifndef _ddekit_condvar_h +#define _ddekit_condvar_h + +/** \file ddekit/condvar.h */ + +#include + +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/include/ddekit/debug.h b/libddekit/include/ddekit/debug.h new file mode 100644 index 00000000..79a8e7b5 --- /dev/null +++ b/libddekit/include/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/include/ddekit/initcall.h b/libddekit/include/ddekit/initcall.h new file mode 100644 index 00000000..b503cc6a --- /dev/null +++ b/libddekit/include/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) \ + static 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/include/ddekit/inline.h b/libddekit/include/ddekit/inline.h new file mode 100644 index 00000000..e59a5c68 --- /dev/null +++ b/libddekit/include/ddekit/inline.h @@ -0,0 +1,2 @@ +#define INLINE __inline__ __attribute__((always_inline)) + diff --git a/libddekit/include/ddekit/interrupt.h b/libddekit/include/ddekit/interrupt.h new file mode 100644 index 00000000..bbabedb2 --- /dev/null +++ b/libddekit/include/ddekit/interrupt.h @@ -0,0 +1,57 @@ +/* + * \brief Hardware-interrupt subsystem + * \author Thomas Friebel + * \author Christian Helmuth + * \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 + +#define DDEKIT_IRQ_PRIO 0x11 + +/** + * 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/include/ddekit/lock.h b/libddekit/include/ddekit/lock.h new file mode 100644 index 00000000..872acad0 --- /dev/null +++ b/libddekit/include/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 + +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/include/ddekit/memory.h b/libddekit/include/ddekit/memory.h new file mode 100644 index 00000000..051a4d9e --- /dev/null +++ b/libddekit/include/ddekit/memory.h @@ -0,0 +1,144 @@ +/* + * \brief Memory subsystem + * \author Thomas Friebel + * \author Christian Helmuth + * \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/include/ddekit/panic.h b/libddekit/include/ddekit/panic.h new file mode 100644 index 00000000..1468675f --- /dev/null +++ b/libddekit/include/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/include/ddekit/pci.h b/libddekit/include/ddekit/pci.h new file mode 100644 index 00000000..9ec7cd4f --- /dev/null +++ b/libddekit/include/ddekit/pci.h @@ -0,0 +1,199 @@ +#ifndef _ddekit_pci_h +#define _ddekit_pci_h + +#include + +/** \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/include/ddekit/pgtab.h b/libddekit/include/ddekit/pgtab.h new file mode 100644 index 00000000..3b68192c --- /dev/null +++ b/libddekit/include/ddekit/pgtab.h @@ -0,0 +1,86 @@ +/* + * \brief Virtual page-table facility + * \author Thomas Friebel + * \author Christian Helmuth + * \date 2006-11-03 + */ + +#ifndef _ddekit_pgtab_h +#define _ddekit_pgtab_h + +#include + +/* 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/include/ddekit/printf.h b/libddekit/include/ddekit/printf.h new file mode 100644 index 00000000..35b0dfa1 --- /dev/null +++ b/libddekit/include/ddekit/printf.h @@ -0,0 +1,33 @@ +#ifndef _ddekit_print_h +#define _ddekit_print_h + +#include + +/** 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); + +/** 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/include/ddekit/resources.h b/libddekit/include/ddekit/resources.h new file mode 100644 index 00000000..e0fa68f0 --- /dev/null +++ b/libddekit/include/ddekit/resources.h @@ -0,0 +1,13 @@ +#ifndef _ddekit_resources_h +#define _ddekit_resources_h + +#include + +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); + +#endif diff --git a/libddekit/include/ddekit/semaphore.h b/libddekit/include/ddekit/semaphore.h new file mode 100644 index 00000000..c959919d --- /dev/null +++ b/libddekit/include/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/include/ddekit/thread.h b/libddekit/include/ddekit/thread.h new file mode 100644 index 00000000..ecd399d9 --- /dev/null +++ b/libddekit/include/ddekit/thread.h @@ -0,0 +1,162 @@ +#ifndef _ddekit_thread_h +#define _ddekit_thread_h + +/** \defgroup DDEKit_threads */ + +#include + +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)); + +/** Terminate a thread + * + * \ingroup DDEKit_threads + */ +void ddekit_thread_terminate(ddekit_thread_t *thread); + +/** Get the name, a thread registered with DDEKit. + * + * \ingroup DDEKit_threads + */ +const char *ddekit_thread_get_name(ddekit_thread_t *thread); + +/** Get unique ID of a DDEKit thread. + * + * \ingroup DDEKit_threads + * + * DDEKit does not allow direct access to the thread data + * structure, since this struct contains L4-specific data types. + * However, applications might want to get some kind of ID related + * to a ddekit_thread, for instance to use it as a Linux-like PID. + */ +int ddekit_thread_get_id(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/include/ddekit/timer.h b/libddekit/include/ddekit/timer.h new file mode 100644 index 00000000..c352475c --- /dev/null +++ b/libddekit/include/ddekit/timer.h @@ -0,0 +1,55 @@ +#ifndef _ddekit_timer_h +#define _ddekit_timer_h + +#include + +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); + +#endif diff --git a/libddekit/include/ddekit/types.h b/libddekit/include/ddekit/types.h new file mode 100644 index 00000000..83d92c65 --- /dev/null +++ b/libddekit/include/ddekit/types.h @@ -0,0 +1,22 @@ +/* + * \brief Types for ddekit (x86 version) + * \author Thomas Friebel + * \author Christian Helmuth + * \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 -- cgit v1.2.3 From 4ab9cd3868caba54bda4c5e1b8b3f79880c1dcd6 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 17 Nov 2009 10:38:35 +0100 Subject: Adapt Makefile to compile DDEKit in Hurd. --- libddekit/Makefile | 50 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index 67d58733..0f4fa552 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -1,9 +1,45 @@ -PKGDIR ?= .. -L4DIR ?= $(PKGDIR)/../.. +# +# 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. -# 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 +dir := libddekit +makemode := library + +libname = libddekit +SRCS= condvar.c init.c initcall.c interrupt.c lock.c malloc.c memory.c \ + panic.c pci.c pgtab-old.c pgtab.c printf.c resources.c semaphore.c \ + thread.c timer.c +LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ + include/ddekit/initcall.h include/ddekit/debug.h \ + include/ddekit/inline.h include/ddekit/panic.h \ + include/ddekit/thread.h include/ddekit/types.h \ + include/ddekit/pgtab.h include/ddekit/printf.h \ + include/ddekit/pci.h include/ddekit/assert.h \ + include/ddekit/interrupt.h include/ddekit/resources.h \ + include/ddekit/memory.h include/ddekit/timer.h \ + include/ddekit/semaphore.h include/dde.h \ + config.h +installhdrs = + +MIGSTUBS = +OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS)) + +HURDLIBS = threads ports + +MIGCOMSFLAGS = -prefix dde_ + +include ../Makeconf -include $(L4DIR)/mk/subdir.mk -- cgit v1.2.3 From 2307c7487acde8295b462895b6625cd7f02b1abd Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 17 Nov 2009 10:41:42 +0100 Subject: We simply use malloc and free. Maybe I can just use macros to replace ddekit_simple_malloc ddekit_simple_free. --- libddekit/malloc.c | 82 +++++++++++------------------------------------------- 1 file changed, 17 insertions(+), 65 deletions(-) (limited to 'libddekit') diff --git a/libddekit/malloc.c b/libddekit/malloc.c index 5f0ae0fc..c3735bdb 100644 --- a/libddekit/malloc.c +++ b/libddekit/malloc.c @@ -1,36 +1,22 @@ -/* - * \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 -#include -#include +/* + Copyright (C) 2009 Free Software Foundation, Inc. + Written by Zheng Da. -#include -#include -#include -#include + This file is part of the GNU Hurd. -/* configuration */ -#define ALLOC_SIZE (4 * L4_PAGESIZE) + 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. -/* malloc pool is a list allocator */ -static l4la_free_t *malloc_pool; -static l4lock_t malloc_lock = L4LOCK_UNLOCKED; + 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 @@ -45,37 +31,7 @@ static l4lock_t malloc_lock = L4LOCK_UNLOCKED; */ 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; + return malloc (size); } @@ -86,9 +42,5 @@ void *ddekit_simple_malloc(unsigned size) */ 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); + free (p); } -- cgit v1.2.3 From 6c2afa3c02447135e2bedd11f0b86833d4533692 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 17 Nov 2009 11:19:05 +0100 Subject: Use libpciaccess to implement it. --- libddekit/include/ddekit/pci.h | 2 +- libddekit/pci.c | 90 ++++++++++++++++-------------------------- 2 files changed, 34 insertions(+), 58 deletions(-) (limited to 'libddekit') diff --git a/libddekit/include/ddekit/pci.h b/libddekit/include/ddekit/pci.h index 9ec7cd4f..5a5fd29b 100644 --- a/libddekit/include/ddekit/pci.h +++ b/libddekit/include/ddekit/pci.h @@ -1,7 +1,7 @@ #ifndef _ddekit_pci_h #define _ddekit_pci_h -#include +#include "ddekit/types.h" /** \defgroup DDEKit_pci */ diff --git a/libddekit/pci.c b/libddekit/pci.c index 35fb7aea..32e02b84 100644 --- a/libddekit/pci.c +++ b/libddekit/pci.c @@ -1,14 +1,5 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include - +#include +#include "ddekit/pci.h" #include "config.h" #define dbg_this 0 @@ -20,7 +11,7 @@ typedef struct ddekit_pci_dev { int bus; /**< bus ID */ int slot; /**< slot ID */ int func; /**< function */ - l4io_pci_dev_t l4dev; /**< L4IO handle */ + struct pci_device *dev; struct ddekit_pci_dev *next; /**< chaining info */ } ddekit_pci_dev_t; @@ -40,49 +31,31 @@ static inline int invalid_device(ddekit_pci_dev_t *d) */ void ddekit_pci_init(void) { - l4io_pdev_t start = 0; - int slots_found = 0; int i; + struct pci_device *pci_dev; + struct pci_device_iterator *dev_iter; /* 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); - } + dev_iter = pci_slot_match_iterator_create (NULL); + while ((pci_dev = pci_device_next (dev_iter)) != NULL) { + if (slots_found == MAX_PCI_DEVS) { + LOGd(dbg_this, "find more than %d pci devices", + slots_found); 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); + ddekit_pci_bus[slots_found].dev = pci_dev; ++slots_found; } + pci_iterator_destroy (dev_iter); } @@ -184,7 +157,7 @@ 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); + return pci_device_cfg_read_u8 (dev->dev, val, pos); else return -1; } @@ -194,7 +167,7 @@ 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); + return pci_device_cfg_read_u16 (dev->dev, val, pos); else return -1; } @@ -204,7 +177,7 @@ 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); + return pci_device_cfg_read_u32 (dev->dev, val, pos); else return -1; } @@ -214,7 +187,7 @@ 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); + return pci_device_cfg_write_u8 (dev->dev, val, pos); else return -1; } @@ -224,7 +197,7 @@ 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); + return pci_device_cfg_write_u16 (dev->dev, val, pos); else return -1; } @@ -234,19 +207,20 @@ 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); + return pci_device_cfg_write_u32 (dev->dev, val, pos); else return -1; } int ddekit_pci_enable_device(struct ddekit_pci_dev *dev) { - return l4io_pci_enable(dev->l4dev.handle); + return pci_device_enable (dev->dev); } int ddekit_pci_disable_device(struct ddekit_pci_dev *dev) { - return l4io_pci_disable(dev->l4dev.handle); + // TODO + return -1; } /******************************************************************************** @@ -264,7 +238,7 @@ int ddekit_pci_disable_device(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_vendor(struct ddekit_pci_dev *dev) { - return dev->l4dev.vendor; + return dev->dev.vendor_id; } @@ -277,7 +251,7 @@ unsigned short ddekit_pci_get_vendor(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_device_id(struct ddekit_pci_dev *dev) { - return dev->l4dev.device; + return dev->dev.device_id; } @@ -290,7 +264,7 @@ unsigned short ddekit_pci_get_device_id(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_sub_vendor(struct ddekit_pci_dev *dev) { - return dev->l4dev.sub_vendor; + return dev->dev.subvendor_id; } @@ -303,7 +277,7 @@ unsigned short ddekit_pci_get_sub_vendor(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_sub_device(struct ddekit_pci_dev *dev) { - return dev->l4dev.sub_device; + return dev->dev.subdevice_id; } @@ -316,7 +290,7 @@ unsigned short ddekit_pci_get_sub_device(struct ddekit_pci_dev *dev) */ unsigned ddekit_pci_get_dev_class(struct ddekit_pci_dev *dev) { - return dev->l4dev.dev_class; + return dev->dev.device_class; } @@ -329,7 +303,7 @@ unsigned ddekit_pci_get_dev_class(struct ddekit_pci_dev *dev) */ unsigned long ddekit_pci_get_irq(struct ddekit_pci_dev *dev) { - return dev->l4dev.irq; + return dev->dev.irq; } @@ -342,7 +316,8 @@ unsigned long ddekit_pci_get_irq(struct ddekit_pci_dev *dev) */ char *ddekit_pci_get_name(struct ddekit_pci_dev *dev) { - return dev->l4dev.name; + // TODO + return NULL; } @@ -355,7 +330,8 @@ char *ddekit_pci_get_name(struct ddekit_pci_dev *dev) */ char *ddekit_pci_get_slot_name(struct ddekit_pci_dev *dev) { - return dev->l4dev.slot_name; + // TODO + return NULL; } @@ -372,7 +348,7 @@ ddekit_pci_res_t *ddekit_pci_get_resource(struct ddekit_pci_dev *dev, unsigned i if (idx > L4IO_PCIDEV_RES) return NULL; - return (ddekit_pci_res_t *)(&(dev->l4dev.res[idx])); + //TODO return (ddekit_pci_res_t *)(&(dev->l4dev.res[idx])); } @@ -383,7 +359,7 @@ ddekit_pci_res_t *ddekit_pci_get_resource(struct ddekit_pci_dev *dev, unsigned i */ void ddekit_pci_set_master(struct ddekit_pci_dev *dev) { - l4io_pci_set_master(dev->l4dev.handle); + //TODO l4io_pci_set_master(dev->l4dev.handle); } int ddekit_pci_irq_enable(int bus, int slot, int func, int pin, int *irq) -- cgit v1.2.3 From e4d24dd6657c5f13e26d5442c1e05feb68e7d348 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 17 Nov 2009 11:21:01 +0100 Subject: link with pciaccess library. --- libddekit/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index 0f4fa552..b2d1a6bc 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -43,3 +43,4 @@ MIGCOMSFLAGS = -prefix dde_ include ../Makeconf +LDFLAGS += -lpciaccess -- cgit v1.2.3 From 53e2cdc12fad42c3b4ddce5bb011273c46d36472 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 17 Nov 2009 11:24:33 +0100 Subject: Remove the code for initializing l4io. --- libddekit/init.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) (limited to 'libddekit') diff --git a/libddekit/init.c b/libddekit/init.c index 0532caed..2104d80f 100644 --- a/libddekit/init.c +++ b/libddekit/init.c @@ -3,33 +3,10 @@ * * \author Thomas Friebel */ -#include -#include -#include - -#include -#include -#include -#include - -/* 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"); - } -} +#include "ddekit/thread.h" void ddekit_init(void) { - ddekit_init_l4io(); ddekit_init_threads(); } -- cgit v1.2.3 From 8ac96c5d189d0259317e38c1d92bb901d1c98e14 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 17 Nov 2009 11:33:50 +0100 Subject: Remove the old pgtable file. --- libddekit/pgtab-old.c | 219 -------------------------------------------------- 1 file changed, 219 deletions(-) delete mode 100644 libddekit/pgtab-old.c (limited to 'libddekit') diff --git a/libddekit/pgtab-old.c b/libddekit/pgtab-old.c deleted file mode 100644 index 2b13698a..00000000 --- a/libddekit/pgtab-old.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * \brief Virtual page-table facility - * \author Thomas Friebel - * \author Christian Helmuth - * \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 - -#include -#include -#include -#include -#include - - -/********************************** - ** 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); - } -} - -- cgit v1.2.3 From 35881fb690c341f53ea3fb969e8d87b69401e49c Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 18 Nov 2009 01:45:36 +0100 Subject: Adapt the implementation of DDEKit threads. --- libddekit/include/ddekit/thread.h | 19 ---- libddekit/thread.c | 213 +++++++++++++++++--------------------- 2 files changed, 97 insertions(+), 135 deletions(-) (limited to 'libddekit') diff --git a/libddekit/include/ddekit/thread.h b/libddekit/include/ddekit/thread.h index ecd399d9..6e505818 100644 --- a/libddekit/include/ddekit/thread.h +++ b/libddekit/include/ddekit/thread.h @@ -3,8 +3,6 @@ /** \defgroup DDEKit_threads */ -#include - struct ddekit_thread; typedef struct ddekit_thread ddekit_thread_t; @@ -118,29 +116,12 @@ void ddekit_thread_wakeup(ddekit_thread_t *thread); */ void ddekit_thread_exit(void) __attribute__((noreturn)); -/** Terminate a thread - * - * \ingroup DDEKit_threads - */ -void ddekit_thread_terminate(ddekit_thread_t *thread); - /** Get the name, a thread registered with DDEKit. * * \ingroup DDEKit_threads */ const char *ddekit_thread_get_name(ddekit_thread_t *thread); -/** Get unique ID of a DDEKit thread. - * - * \ingroup DDEKit_threads - * - * DDEKit does not allow direct access to the thread data - * structure, since this struct contains L4-specific data types. - * However, applications might want to get some kind of ID related - * to a ddekit_thread, for instance to use it as a Linux-like PID. - */ -int ddekit_thread_get_id(ddekit_thread_t *thread); - /** Hint that this thread is done and may be scheduled somehow. * * \ingroup DDEKit_threads diff --git a/libddekit/thread.c b/libddekit/thread.c index db767dc9..a4566d77 100644 --- a/libddekit/thread.c +++ b/libddekit/thread.c @@ -1,114 +1,68 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - #include #include +#include +#include +#include + +#include "ddekit/thread.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; + struct cthread thread; }; -/** - * 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); +static void setup_thread (cthread_t *t, const char *name) { + if (name) { + const char *cpy = NULL; - td->data=NULL; - td->sleep_cv = ddekit_condvar_init(); - td->l4thread = l4thread_myself(); - td->name = pname; + cpy = malloc (strlen (name) + 1); + if (cpy == NULL) + error (0, 0, "fail to allocate memory"); + else + strcpy (cpy, name); - strcpy(pname, name); + cthread_set_name (t, name); + } - l4thread_data_set_current(tlskey_thread, td); - - return td; + /* + * ldata isn't used by cthread. Since cthread isn't exposed to + * the user of this library. It's very safe to store + * the condition variable in ldata. + */ + sleep_cond = condition_alloc (); + condition_init (sleep_cond); + cthread_set_ldata (t, sleep_cond); } -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); +ddekit_thread_t *ddekit_thread_setup_myself(const char *name) { + ddekit_thread_t *td = ddekit_thread_myself(); - /* call thread routine */ - su.fun(su.arg); + setup_thread (&td->thread, name); + return td; } 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; - + condition_t sleep_cond; + + // TODO not very sure whether I should let the thread suspend + // before initialization is completed. + td = (ddekit_thread_t *) cthread_fork (fun, arg); + setup_thread (&td->thread, name); return td; } ddekit_thread_t *ddekit_thread_myself(void) { - return (ddekit_thread_t *) l4thread_data_get_current(tlskey_thread); + return (ddekit_thread_t *) cthread_self (); } void ddekit_thread_set_data(ddekit_thread_t *thread, void *data) { - thread->data = data; + // TODO not very sure whether I should call cthread_set_ldata + // or cthread_set_data. + cthread_set_data ((cthread_t) thread, data); } void ddekit_thread_set_my_data(void *data) { @@ -116,7 +70,7 @@ void ddekit_thread_set_my_data(void *data) { } void *ddekit_thread_get_data(ddekit_thread_t *thread) { - return thread->data; + return cthread_data ((cthread_t) thread); } void *ddekit_thread_get_my_data() { @@ -124,72 +78,99 @@ void *ddekit_thread_get_my_data() { } void ddekit_thread_msleep(unsigned long msecs) { - l4thread_sleep(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) { - l4_busy_wait_us(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) { - l4_busy_wait_ns(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) { ddekit_thread_t *td; + condition_t sleep_cond; td = ddekit_thread_myself(); + sleep_cond = ddekit_thread_get_data (&td->thread); - ddekit_condvar_wait(td->sleep_cv, lock); + mutex_lock (lock); + // TODO condition_wait cannot guarantee that the thread is + // woke up by another thread, maybe by signals. + // Does it matter here? + condition_wait (sleep_cond, lock); + mutex_unlock (lock); } void ddekit_thread_wakeup(ddekit_thread_t *td) { - ddekit_condvar_signal(td->sleep_cv); -} - -void ddekit_thread_exit() { ddekit_thread_t *td; + condition_t sleep_cond; td = ddekit_thread_myself(); - - l4thread_exit(); + sleep_cond = ddekit_thread_get_data (&td->thread); - ddekit_slab_free(ddekit_stack_slab ,td->stack); - + condition_signal (sleep_cond); } -void ddekit_thread_terminate(ddekit_thread_t *t) -{ - l4thread_shutdown(t->l4thread); -} +void ddekit_thread_exit() { + const char *name; + condition_t sleep_cond; + cthread_t t = cthread_self (); -const char *ddekit_thread_get_name(ddekit_thread_t *thread) { - return thread->name; + // TODO I hope I don't need a lock to protect ldata and name. + + /* I have to free the sleep condition variable + * before the thread exits. */ + sleep_cond = cthread_ldata (t); + cthread_set_ldata (t, NULL); + condition_free (sleep_cond); + + name = cthread_name (t); + cthread_set_name (t, NULL); + free (name); + + cthread_exit (0); } -int ddekit_thread_get_id(ddekit_thread_t *t) -{ - return t->l4thread; +const char *ddekit_thread_get_name(ddekit_thread_t *thread) { + return cthread_name ((cthread_t) thread); } void ddekit_thread_schedule(void) { - l4_yield(); + cthread_yield(); } void ddekit_yield(void) { - l4_yield(); + cthread_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); + // TODO maybe the name has already been set. + cthread_set_name (cthread_self (), "main"); } -- cgit v1.2.3 From bcbb19bbe30d89a24591d632bbed62123dbef8be Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 18 Nov 2009 02:19:17 +0100 Subject: Adapt the implementation of lock. TODO: the implementation of the owner of lock hasn't been adapted. --- libddekit/include/ddekit/lock.h | 2 +- libddekit/lock.c | 42 +++++++++-------------------------------- 2 files changed, 10 insertions(+), 34 deletions(-) (limited to 'libddekit') diff --git a/libddekit/include/ddekit/lock.h b/libddekit/include/ddekit/lock.h index 872acad0..dd398b38 100644 --- a/libddekit/include/ddekit/lock.h +++ b/libddekit/include/ddekit/lock.h @@ -52,7 +52,7 @@ static int ddekit_lock_try_lock(ddekit_lock_t *mtx); // returns 0 on success, ! static void ddekit_lock_unlock (ddekit_lock_t *mtx); // inline implementation or inline call to non-inline implementation -#include +#include "ddekit/inline.h" static INLINE void ddekit_lock_init_unlocked(ddekit_lock_t *mtx) { _ddekit_lock_init(mtx); diff --git a/libddekit/lock.c b/libddekit/lock.c index 0f451dfd..1e61b8b6 100644 --- a/libddekit/lock.c +++ b/libddekit/lock.c @@ -1,58 +1,34 @@ -#include -#include +#include -#include -#include +#include "ddekit/lock.h" #define DDEKIT_DEBUG_LOCKS 0 struct ddekit_lock { - l4lock_t lock; + struct mutex lock; }; void _ddekit_lock_init(struct ddekit_lock **mtx) { - *mtx = (struct ddekit_lock *) ddekit_simple_malloc(sizeof(struct ddekit_lock)); - (*mtx)->lock = L4LOCK_UNLOCKED; + *mtx = (struct ddekit_lock *) mutex_alloc (); + mutex_init (*mtx); } void _ddekit_lock_deinit(struct ddekit_lock **mtx) { - ddekit_simple_free(*mtx); + mutex_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 + mutex_lock (&(*mtx)->lock); } /* 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; + return !mutex_try_lock (&(*mtx)->lock); } 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 + mutex_unlock (&(*mtx)->lock); } -- cgit v1.2.3 From ece7285d5f8122ee120d3f5ceee1b514c734dec5 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 18 Nov 2009 02:54:34 +0100 Subject: Check in the implementation of the owner of a lock. --- libddekit/lock.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/lock.c b/libddekit/lock.c index 1e61b8b6..f64d571b 100644 --- a/libddekit/lock.c +++ b/libddekit/lock.c @@ -33,6 +33,9 @@ void _ddekit_lock_unlock(struct ddekit_lock **mtx) { int _ddekit_lock_owner(struct ddekit_lock **mtx) { - return (int)l4lock_owner(&(*mtx)->lock); + /* 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)->lock.holder; } -- cgit v1.2.3 From 31452a09c0cf1e9488b75bcff156923ea4fc1a08 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 18 Nov 2009 03:00:48 +0100 Subject: fix a bug in thread.c. --- libddekit/thread.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'libddekit') diff --git a/libddekit/thread.c b/libddekit/thread.c index a4566d77..ddd5c7ef 100644 --- a/libddekit/thread.c +++ b/libddekit/thread.c @@ -116,23 +116,18 @@ void ddekit_thread_sleep(ddekit_lock_t *lock) { condition_t sleep_cond; td = ddekit_thread_myself(); - sleep_cond = ddekit_thread_get_data (&td->thread); + sleep_cond = ddekit_thread_get_data (td); - mutex_lock (lock); // TODO condition_wait cannot guarantee that the thread is // woke up by another thread, maybe by signals. // Does it matter here? condition_wait (sleep_cond, lock); - mutex_unlock (lock); } void ddekit_thread_wakeup(ddekit_thread_t *td) { - ddekit_thread_t *td; condition_t sleep_cond; - td = ddekit_thread_myself(); - sleep_cond = ddekit_thread_get_data (&td->thread); - + sleep_cond = ddekit_thread_get_data (td); condition_signal (sleep_cond); } -- cgit v1.2.3 From b537f6cede63b0e55e82a2ee1467d094200d953e Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 21 Nov 2009 00:47:01 +0100 Subject: Emulate the timer in the Hurd. --- libddekit/include/ddekit/timer.h | 4 +- libddekit/timer.c | 107 ++++++++++++++++++++------------------- 2 files changed, 59 insertions(+), 52 deletions(-) (limited to 'libddekit') diff --git a/libddekit/include/ddekit/timer.h b/libddekit/include/ddekit/timer.h index c352475c..a57c8fce 100644 --- a/libddekit/include/ddekit/timer.h +++ b/libddekit/include/ddekit/timer.h @@ -1,7 +1,9 @@ #ifndef _ddekit_timer_h #define _ddekit_timer_h -#include +#include "ddekit/thread.h" + +#define jiffies fetch_jiffies() enum { diff --git a/libddekit/timer.c b/libddekit/timer.c index b1af99bf..d0a6ccc0 100644 --- a/libddekit/timer.c +++ b/libddekit/timer.c @@ -1,20 +1,14 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include +#include +#include +#include + +#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. @@ -22,7 +16,6 @@ * 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 @@ -36,8 +29,8 @@ typedef struct _timer 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 struct mutex timer_lock = MUTEX_INITIALIZER; ///< lock to access timer_list +static cthread_t timer_thread; ///< 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 @@ -58,20 +51,27 @@ static void dump_list(char *msg) #endif } +int fetch_jiffies () +{ + struct timeval tv; + long long j; + + 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) { - 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)) + if (timer_thread == NULL) return; ddekit_sem_up(notify_semaphore); @@ -91,7 +91,7 @@ int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout) t->expires = timeout; t->next = NULL; - l4lock_lock(&timer_lock); + mutex_lock (&timer_lock); t->id = timer_id_ctr++; @@ -122,7 +122,7 @@ int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout) __notify_timer_thread(); } - l4lock_unlock(&timer_lock); + mutex_unlock (&timer_lock); dump_list("after add"); @@ -135,7 +135,7 @@ int ddekit_del_timer(int timer) ddekit_timer_t *it, *it_next; int ret = -1; - l4lock_lock(&timer_lock); + mutex_lock (&timer_lock); /* no timer? */ if (!timer_list) { @@ -176,7 +176,7 @@ int ddekit_del_timer(int timer) } out: - l4lock_unlock(&timer_lock); + mutex_unlock (&timer_lock); dump_list("after del"); @@ -195,7 +195,7 @@ int ddekit_timer_pending(int timer) ddekit_timer_t *t = NULL; int r = 0; - l4lock_lock(&timer_lock); + mutex_lock (&timer_lock); t = timer_list; while (t) { @@ -206,7 +206,7 @@ int ddekit_timer_pending(int timer) t = t->next; } - l4lock_unlock(&timer_lock); + mutex_unlock (&timer_lock); return r; } @@ -222,8 +222,7 @@ 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)); + Assert(timer_lock.holder == timer_thread); if (timer_list && (timer_list->expires <= jiffies)) { @@ -248,27 +247,24 @@ enum */ static inline int __timer_sleep(unsigned to) { - l4_umword_t dummy; - l4_msgdope_t res; - int err = 0; - l4lock_unlock(&timer_lock); + mutex_unlock (&timer_lock); - if (to == DDEKIT_TIMEOUT_NEVER) { - ddekit_sem_down(notify_semaphore); - } - else { + 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); + ddekit_printf("Going to sleep for %lu µs (%lu ms)\n", to * 1000, to); #endif - err = ddekit_sem_down_timed(notify_semaphore, to); + err = ddekit_sem_down_timed(notify_semaphore, to); #if 0 - ddekit_printf("err: %x\n", err); + ddekit_printf("err: %x\n", err); #endif - } + } - l4lock_lock(&timer_lock); + mutex_lock (&timer_lock); return (err ? 1 : 0); } @@ -283,9 +279,9 @@ static void ddekit_timer_thread(void *arg) l4thread_set_prio(l4thread_myself(), 0x11); #endif - l4thread_started(0); +// l4thread_started(0); - l4lock_lock(&timer_lock); + mutex_lock (&timer_lock); while (1) { ddekit_timer_t *timer = NULL; unsigned long to = DDEKIT_TIMEOUT_NEVER; @@ -303,13 +299,14 @@ static void ddekit_timer_thread(void *arg) __timer_sleep(to); while ((timer = get_next_timer()) != NULL) { - l4lock_unlock(&timer_lock); + mutex_unlock (&timer_lock); //ddekit_printf("doing timer fn @ %p\n", timer->fn); timer->fn(timer->args); ddekit_simple_free(timer); - l4lock_lock(&timer_lock); + mutex_lock (&timer_lock); } } + // TODO how is the thread terminated? } ddekit_thread_t *ddekit_get_timer_thread() @@ -320,10 +317,18 @@ ddekit_thread_t *ddekit_get_timer_thread() void ddekit_init_timers(void) { - l4_tsc_init(L4_TSC_INIT_AUTO); + error_t err; + struct timeval tp; + + 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; - /* 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)); + timer_thread = cthread_fork ((cthread_fn_t) timer_function, 0); + cthread_detach (timer_thread); } -- cgit v1.2.3 From 7c5d267799af896d4bc9e7a03ece141a6764c12c Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 21 Nov 2009 06:40:42 +0100 Subject: Record the thread who holds the lock by ourselves. cthreads mutex might contain the holder only when WAITDEBUG is defined. I think it's better to implement it by ourselves. --- libddekit/lock.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'libddekit') diff --git a/libddekit/lock.c b/libddekit/lock.c index f64d571b..bf643e65 100644 --- a/libddekit/lock.c +++ b/libddekit/lock.c @@ -6,11 +6,16 @@ struct ddekit_lock { struct mutex lock; + cthread_t helder; }; void _ddekit_lock_init(struct ddekit_lock **mtx) { - *mtx = (struct ddekit_lock *) mutex_alloc (); - mutex_init (*mtx); + struct ddekit_lock *lock; + + lock = (struct ddekit_lock *) ddekit_simple_malloc (sizeof *lock); + mutex_init (&lock->lock); + lock->helder = NULL; + *mtx = lock; } void _ddekit_lock_deinit(struct ddekit_lock **mtx) { @@ -20,15 +25,22 @@ void _ddekit_lock_deinit(struct ddekit_lock **mtx) { void _ddekit_lock_lock(struct ddekit_lock **mtx) { mutex_lock (&(*mtx)->lock); + (*mtx)->helder = cthread_self (); } /* returns 0 on success, != 0 if it would block */ int _ddekit_lock_try_lock(struct ddekit_lock **mtx) { - return !mutex_try_lock (&(*mtx)->lock); + if (mutex_try_lock (&(*mtx)->lock)) { /* lock succeessfully */ + (*mtx)->helder = cthread_self (); + return 0; + } + return -1; } void _ddekit_lock_unlock(struct ddekit_lock **mtx) { mutex_unlock (&(*mtx)->lock); + // TODO I wonder if it can cause any trouble. + (*mtx)->helder = NULL; } @@ -36,6 +48,6 @@ 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)->lock.holder; + return (int) (*mtx)->holder; } -- cgit v1.2.3 From 1467ade7d8fd55511e6f94abd41078eab90b57b0 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 21 Nov 2009 12:52:14 +0100 Subject: Implement the semaphore (in thread.c). --- libddekit/Makefile | 4 +- libddekit/semaphore.c | 48 --------- libddekit/thread.c | 294 ++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 276 insertions(+), 70 deletions(-) delete mode 100644 libddekit/semaphore.c (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index b2d1a6bc..e9daa648 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -20,7 +20,7 @@ makemode := library libname = libddekit SRCS= condvar.c init.c initcall.c interrupt.c lock.c malloc.c memory.c \ - panic.c pci.c pgtab-old.c pgtab.c printf.c resources.c semaphore.c \ + panic.c pci.c pgtab-old.c pgtab.c printf.c resources.c list.c \ thread.c timer.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ include/ddekit/initcall.h include/ddekit/debug.h \ @@ -31,7 +31,7 @@ LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ include/ddekit/interrupt.h include/ddekit/resources.h \ include/ddekit/memory.h include/ddekit/timer.h \ include/ddekit/semaphore.h include/dde.h \ - config.h + config.h list.h installhdrs = MIGSTUBS = diff --git a/libddekit/semaphore.c b/libddekit/semaphore.c deleted file mode 100644 index 6fbb7f35..00000000 --- a/libddekit/semaphore.c +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include - -#include - -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 index ddd5c7ef..a095db2f 100644 --- a/libddekit/thread.c +++ b/libddekit/thread.c @@ -4,17 +4,70 @@ #include #include +#include "ddekit/semaphore.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; + condition_t sleep_cond; + /* point to the thread who has the private data. */ + struct ddekit_thread *thread; + mach_msg_header_t wakeupmsg; + +} + struct ddekit_thread { struct cthread thread; }; +struct ddekit_sem +{ + spin_lock_t lock; + /* A list of thread waiting for the semaphore. */ + struct list head; + int value; +}; + +/* 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 (cthread_t *t, const char *name) { + error_t err; + struct _ddekit_private_data *private_data; + if (name) { const char *cpy = NULL; @@ -32,9 +85,21 @@ static void setup_thread (cthread_t *t, const char *name) { * the user of this library. It's very safe to store * the condition variable in ldata. */ - sleep_cond = condition_alloc (); - condition_init (sleep_cond); - cthread_set_ldata (t, sleep_cond); + + private_data = (struct _ddekit_private_data *) + ddekit_simple_malloc (sizeof (*private_data)); + + private_data->sleep_cond = condition_alloc (); + condition_init (private_data->sleep_cond); + + private_data->list = {&private_data->list, &private_data->list}; + private_data->thread = t; + + err = _create_wakeupmsg (private_data); + // TODO I need to change this. + assert_perror (err); + + cthread_set_ldata (t, private_data); } ddekit_thread_t *ddekit_thread_setup_myself(const char *name) { @@ -46,11 +111,11 @@ ddekit_thread_t *ddekit_thread_setup_myself(const char *name) { ddekit_thread_t *ddekit_thread_create(void (*fun)(void *), void *arg, const char *name) { ddekit_thread_t *td; - condition_t sleep_cond; - // TODO not very sure whether I should let the thread suspend + // TODO I should let the thread suspend // before initialization is completed. td = (ddekit_thread_t *) cthread_fork (fun, arg); + cthread_detach (&td->thread); setup_thread (&td->thread, name); return td; } @@ -60,8 +125,6 @@ ddekit_thread_t *ddekit_thread_myself(void) { } void ddekit_thread_set_data(ddekit_thread_t *thread, void *data) { - // TODO not very sure whether I should call cthread_set_ldata - // or cthread_set_data. cthread_set_data ((cthread_t) thread, data); } @@ -112,37 +175,33 @@ void ddekit_thread_nsleep(unsigned long nsecs) { } void ddekit_thread_sleep(ddekit_lock_t *lock) { - ddekit_thread_t *td; - condition_t sleep_cond; - - td = ddekit_thread_myself(); - sleep_cond = ddekit_thread_get_data (td); + struct _ddekit_private_data *data = cthread_ldata (cthread_self ()); // TODO condition_wait cannot guarantee that the thread is // woke up by another thread, maybe by signals. // Does it matter here? - condition_wait (sleep_cond, lock); + condition_wait (data->sleep_cond, lock); } -void ddekit_thread_wakeup(ddekit_thread_t *td) { - condition_t sleep_cond; +void dekit_thread_wakeup(ddekit_thread_t *td) { + struct _ddekit_private_data *data = cthread_ldata (cthread_self ()); - sleep_cond = ddekit_thread_get_data (td); - condition_signal (sleep_cond); + condition_signal (data->sleep_cond); } void ddekit_thread_exit() { const char *name; - condition_t sleep_cond; + struct _ddekit_private_data *data; cthread_t t = cthread_self (); // TODO I hope I don't need a lock to protect ldata and name. /* I have to free the sleep condition variable * before the thread exits. */ - sleep_cond = cthread_ldata (t); + data = cthread_ldata (t); cthread_set_ldata (t, NULL); - condition_free (sleep_cond); + condition_free (data->sleep_cond); + ddekit_simple_free (data); name = cthread_name (t); cthread_set_name (t, NULL); @@ -169,3 +228,198 @@ void ddekit_init_threads() { // TODO maybe the name has already been set. cthread_set_name (cthread_self (), "main"); } + +/* Block THREAD. */ +static error_t _timedblock (struct _ddekit_private_data *data, + const struct timespec *abstime) +{ + error_t err; + mach_msg_header_t msg; + mach_msg_timeout_t timeout; + struct timeval now; + + /* We have an absolute time and now we have to convert it to a + relative time. Arg. */ + + err = gettimeofday(&now, NULL); + assert (! err); + + if (now.tv_sec > abstime->tv_sec + || (now.tv_sec == abstime->tv_sec + && now.tv_usec > ((abstime->tv_nsec + 999) / 1000))) + return ETIMEDOUT; + + timeout = (abstime->tv_sec - now.tv_sec) * 1000; + + if (((abstime->tv_nsec + 999) / 1000) >= now.tv_usec) + timeout -= (((abstime->tv_nsec + 999) / 1000) + - now.tv_usec + 999) / 1000; + else + /* Need to do a carry. */ + timeout -= 1000 + ((abstime->tv_nsec + 999999) / 1000000) + - (now.tv_usec + 999) / 1000; + + 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 (sem_t *restrict sem, + const struct timespec *restrict timeout) +{ + struct ddekit_private_data *self_private_data; + + spin_lock (&sem->lock); + if (sem->value > 0) { + /* Successful down. */ + sem->value --; + spin_unlock (&sem->__lock); + return 0; + } + + if (timeout && (timeout->tv_nsec < 0 + || timeout->tv_nsec >= 1000000000)) { + errno = EINVAL; + return -1; + } + + /* Add ourselves to the queue. */ + self_private_data = cthread_ldata (cthread_self ()); + + add_entry_head (&sem->head, (struct list *) self_private_data); + spin_unlock (&sem->lock); + + /* Block the thread. */ + if (timeout) { + error_t err; + + err = _timedblock (self_private_data, 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); + + spin_lock (&sem->lock); + remove_entry ((struct list *) self_private_data); + spin_unlock (&sem->lock); + + errno = err; + return -1; + } + } + else + _block (self_private_data); + + 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 = SPIN_LOCK_INITIALIZER; + sem->head = {&sem->head, &sem->head}; + sem->value = value; + return sem; +} + +void ddekit_sem_deinit(ddekit_sem_t *sem) { + if (!EMPTY_ENTRY (&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, NULL); +} + +/* returns 0 on success, != 0 when it would block */ +int ddekit_sem_down_try(ddekit_sem_t *sem) { + spin_lock (&sem->lock); + if (sem->value > 0) { + /* Successful down. */ + sem->value --; + spin_unlock (&sem->lock); + return 0; + } + 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 */ + struct timespec timeout; + + timeout.tv_sec = timo / 1000; + timeout.tv_nsec = (timo % 1000) * 1000 * 1000; + return __sem_timedwait_internal (sem, &timeout); +} + +void ddekit_sem_up(ddekit_sem_t *sem) { + struct _ddekit_thread_data *wakeup; + + spin_lock (&sem->lock); + if (sem->value > 0) { + /* Do a quick up. */ + assert (EMPTY_LIST (&sem->head)); + sem->value ++; + spin_unlock (&sem->lock); + return 0; + } + + if (EMPTY_LIST (&sem->head)) { + /* No one waiting. */ + sem->value = 1; + spin_unlock (&sem->lock); + return 0; + } + + /* Wake someone up. */ + + /* First dequeue someone. */ + wakeup = (struct _ddekit_private_data *) remove_entry_end (&sem->head); + + /* Then drop the lock and transfer control. */ + spin_unlock (&sem->lock); + if (wakeup) + _thread_wakeup (wakeup); + + return 0; +} + -- cgit v1.2.3 From 53bf830ac028cb07170ff891c4a080a57f2db458 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 21 Nov 2009 12:53:26 +0100 Subject: Add the implementation of list, used by semaphore. --- libddekit/list.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ libddekit/list.h | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 libddekit/list.c create mode 100644 libddekit/list.h (limited to 'libddekit') diff --git a/libddekit/list.c b/libddekit/list.c new file mode 100644 index 00000000..992ea9ad --- /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_ENTRY (entry)) + return NULL; + + remove_entry (entry); + return entry; +} + +struct list *remove_entry_end (struct list *head) +{ + struct list *entry = head->prev; + + if (EMPTY_ENTRY (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 + +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 -- cgit v1.2.3 From d33a9a7e6a46543156a8f07b8e684b171c2ba456 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 3 Dec 2009 13:59:14 +0100 Subject: The implementation of condition variables. ddekit_condvar_wait_timed hasn't been implemented as it is only used by freebsd drivers. --- libddekit/condvar.c | 94 ++++++-------------------------------- libddekit/include/ddekit/condvar.h | 2 - 2 files changed, 15 insertions(+), 81 deletions(-) (limited to 'libddekit') diff --git a/libddekit/condvar.c b/libddekit/condvar.c index a495cf92..96e28c07 100644 --- a/libddekit/condvar.c +++ b/libddekit/condvar.c @@ -4,105 +4,41 @@ * * \author Thomas Friebel */ -#include -#include -#include +#include -#include -#include -#include +#include "ddekit/condvar.h" struct ddekit_condvar { - unsigned waiters; - unsigned signals; - l4lock_t lock; - l4semaphore_t sem; - l4semaphore_t handshake; + struct condition cond; }; 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); + cvp = condition_alloc (); + condition_init (cvp); return cvp; } void ddekit_condvar_wait(ddekit_condvar_t *cvp, ddekit_lock_t *mp) { - ddekit_condvar_wait_timed(cvp, mp, -1); + /* This isn't nice. The encapsulation is broken. + * TODO I can merge the two files condvar.c and lock.c. */ + condition_wait (&cvp->cond, (struct mutex *) mp); } -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; +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) { - 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); - } + condition_signal (&cvp->cond); } 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; isem); - } - l4lock_unlock(&cvp->lock); - for (i=0; ihandshake); - } - } else { - l4lock_unlock(&cvp->lock); - } + condition_broadcast (&cvp->cond); } diff --git a/libddekit/include/ddekit/condvar.h b/libddekit/include/ddekit/condvar.h index b6dc4bd3..ba87358d 100644 --- a/libddekit/include/ddekit/condvar.h +++ b/libddekit/include/ddekit/condvar.h @@ -3,8 +3,6 @@ /** \file ddekit/condvar.h */ -#include - struct ddekit_condvar; typedef struct ddekit_condvar ddekit_condvar_t; -- cgit v1.2.3 From 0441d40c8f86487734d89d08f9f2023a64410489 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 3 Dec 2009 14:20:42 +0100 Subject: Modify resource.c. --- libddekit/include/ddekit/resources.h | 2 +- libddekit/resources.c | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'libddekit') diff --git a/libddekit/include/ddekit/resources.h b/libddekit/include/ddekit/resources.h index e0fa68f0..dfbb1322 100644 --- a/libddekit/include/ddekit/resources.h +++ b/libddekit/include/ddekit/resources.h @@ -1,7 +1,7 @@ #ifndef _ddekit_resources_h #define _ddekit_resources_h -#include +#include "ddekit/types.h" int ddekit_request_dma(int nr); int ddekit_release_dma(int nr); diff --git a/libddekit/resources.c b/libddekit/resources.c index d4d421c4..4bbd2db9 100644 --- a/libddekit/resources.c +++ b/libddekit/resources.c @@ -1,15 +1,21 @@ -#include +#include -#include +#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 @@ -18,7 +24,7 @@ int ddekit_release_dma(int nr) { * \return -1 error */ int ddekit_request_io(ddekit_addr_t start, ddekit_addr_t count) { - return l4io_request_region(start, count); + return ioperm (start, count, 1); } /** Release an IO region. @@ -27,7 +33,7 @@ int ddekit_request_io(ddekit_addr_t start, ddekit_addr_t count) { * \return <0 error */ int ddekit_release_io(ddekit_addr_t start, ddekit_addr_t count) { - return l4io_release_region(start, count); + return ioperm (start, count, 0); } /** Request a memory region. @@ -37,6 +43,7 @@ int ddekit_release_io(ddekit_addr_t start, ddekit_addr_t count) { * \return -1 error */ int ddekit_request_mem(ddekit_addr_t start, ddekit_addr_t count, ddekit_addr_t *vaddr) { +#if 0 ddekit_addr_t v; v = l4io_request_mem_region(start, count, 0); @@ -45,6 +52,8 @@ int ddekit_request_mem(ddekit_addr_t start, ddekit_addr_t count, ddekit_addr_t * return 0; } else return -1; +#endif + return -1; } /** Release memory region. @@ -53,5 +62,8 @@ int ddekit_request_mem(ddekit_addr_t start, ddekit_addr_t count, ddekit_addr_t * * \return <0 error */ int ddekit_release_mem(ddekit_addr_t start, ddekit_addr_t count) { +#if 0 return l4io_release_mem_region(start, count); +#endif + return -1; } -- cgit v1.2.3 From 41a14fbb798e85fcb26b1a95ea72daeda9ec2004 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 3 Dec 2009 14:43:55 +0100 Subject: Implement a faked slab cache. --- libddekit/Makefile | 2 +- libddekit/init.c | 2 + libddekit/memory.c | 277 +++-------------------------------------------------- 3 files changed, 16 insertions(+), 265 deletions(-) (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index e9daa648..59e5c5a9 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -21,7 +21,7 @@ makemode := library libname = libddekit SRCS= condvar.c init.c initcall.c interrupt.c lock.c malloc.c memory.c \ panic.c pci.c pgtab-old.c pgtab.c printf.c resources.c list.c \ - thread.c timer.c + thread.c timer.c kmem.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ include/ddekit/initcall.h include/ddekit/debug.h \ include/ddekit/inline.h include/ddekit/panic.h \ diff --git a/libddekit/init.c b/libddekit/init.c index 2104d80f..9708ba1d 100644 --- a/libddekit/init.c +++ b/libddekit/init.c @@ -7,6 +7,8 @@ void ddekit_init(void) { + extern void linux_kmem_init (); ddekit_init_threads(); + linux_kmem_init (); } diff --git a/libddekit/memory.c b/libddekit/memory.c index b6db0cac..93853e55 100644 --- a/libddekit/memory.c +++ b/libddekit/memory.c @@ -10,16 +10,9 @@ * FIXME check thread-safety and add locks where appropriate */ -#include -#include -#include -#include +#include "ddekit/memory.h" -#include -#include -#include -#include -#include +extern void * linux_kmalloc (unsigned int size, int priority); /**************** @@ -56,21 +49,6 @@ struct ddekit_pcache }; -/* 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 * @@ -82,88 +60,8 @@ static l4_uint32_t pcache_num_entries = 1; */ 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 ** *******************************/ @@ -171,132 +69,16 @@ static inline struct ddekit_pcache *_get_free_cache_entry(int contig) /* 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 size; 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; + return linux_kmalloc (slab->size, 0); } @@ -305,9 +87,7 @@ void *ddekit_slab_alloc(struct ddekit_slab * slab) */ void ddekit_slab_free(struct ddekit_slab * slab, void *objp) { - l4lock_lock(&slab->lock); - l4slab_free(&slab->cache, objp); - l4lock_unlock(&slab->lock); + linux_kfree (objp); } @@ -316,7 +96,9 @@ void ddekit_slab_free(struct ddekit_slab * slab, void *objp) */ void ddekit_slab_set_data(struct ddekit_slab * slab, void *data) { +#if 0 l4slab_set_data(&slab->cache, data); +#endif } @@ -325,7 +107,9 @@ void ddekit_slab_set_data(struct ddekit_slab * slab, void *data) */ void *ddekit_slab_get_data(struct ddekit_slab * slab) { +#if 0 return l4slab_get_data(&slab->cache); +#endif } @@ -336,7 +120,6 @@ void *ddekit_slab_get_data(struct ddekit_slab * slab) */ void ddekit_slab_destroy (struct ddekit_slab * slab) { - l4slab_destroy(&slab->cache); ddekit_simple_free(slab); } @@ -352,19 +135,10 @@ void ddekit_slab_destroy (struct ddekit_slab * slab) 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->size = size; slab->contiguous = contiguous; - return slab; } @@ -380,11 +154,7 @@ struct ddekit_slab * ddekit_slab_init(unsigned size, int contiguous) */ void ddekit_large_free(void *objp) { - /* clear PTEs */ - ddekit_pgtab_clear_region(objp, PTE_TYPE_LARGE); - - /* release */ - l4dm_mem_release(objp); + return linux_kfree (objp); } @@ -395,29 +165,8 @@ void ddekit_large_free(void *objp) */ 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; + // TODO I hope linux_kmalloc can provide large enough pages. + return linux_kmalloc (size, 0); } -- cgit v1.2.3 From 09b6164c0b107cae65a48c2e070c83a4da676bec Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 3 Dec 2009 16:39:07 +0100 Subject: Implement physical <--> virtual address mapping. --- libddekit/include/ddekit/pgtab.h | 2 +- libddekit/kmem.c | 496 +++++++++++++++++++++++++++++++++++++++ libddekit/pgtab.c | 138 ++--------- 3 files changed, 511 insertions(+), 125 deletions(-) create mode 100644 libddekit/kmem.c (limited to 'libddekit') diff --git a/libddekit/include/ddekit/pgtab.h b/libddekit/include/ddekit/pgtab.h index 3b68192c..8964b713 100644 --- a/libddekit/include/ddekit/pgtab.h +++ b/libddekit/include/ddekit/pgtab.h @@ -8,7 +8,7 @@ #ifndef _ddekit_pgtab_h #define _ddekit_pgtab_h -#include +#include "ddekit/types.h" /* FIXME Region types may be defined by pgtab users. Do we really need them * here? */ diff --git a/libddekit/kmem.c b/libddekit/kmem.c new file mode 100644 index 00000000..4769190e --- /dev/null +++ b/libddekit/kmem.c @@ -0,0 +1,496 @@ +/* + * Linux memory allocation. + * + * Copyright (C) 1996 The University of Utah and the Computer Systems + * Laboratory at the University of Utah (CSL) + * + * 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, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Shantanu Goel, University of Utah CSL + * + */ + +#include +#include +#include "mach_U.h" +#include +#include + +#include "util.h" +#include "vm_param.h" + +extern int printf (const char *, ...); + +/* Amount of memory to reserve for Linux memory allocator. + We reserve 64K chunks to stay within DMA limits. + Increase MEM_CHUNKS if the kernel is running out of memory. */ +#define MEM_CHUNK_SIZE (64 * 1024) +#define MEM_CHUNKS 7 + +/* Mininum amount that linux_kmalloc will allocate. */ +#define MIN_ALLOC 12 + +#ifndef NBPW +#define NBPW 32 +#endif + +/* Memory block header. */ +struct blkhdr +{ + unsigned short free; /* 1 if block is free */ + unsigned short size; /* size of block */ +}; + +/* This structure heads a page allocated by linux_kmalloc. */ +struct pagehdr +{ + unsigned size; /* size (multiple of PAGE_SIZE) */ + struct pagehdr *next; /* next header in list */ +}; + +/* This structure describes a memory chunk. */ +struct chunkhdr +{ + vm_address_t start; /* start address */ + vm_address_t pstart; /* start physical address */ + vm_address_t end; /* end address */ + unsigned long bitmap; /* busy/free bitmap of pages */ +}; + +unsigned long __get_free_pages (unsigned long order, int dma); +void free_pages (unsigned long addr, unsigned long order); + +static struct mutex mem_lock = MUTEX_INITIALIZER; + +/* Chunks from which pages are allocated. */ +static struct chunkhdr pages_free[MEM_CHUNKS]; + +/* Memory list maintained by linux_kmalloc. */ +static struct pagehdr *memlist; + +/* Some statistics. */ +int num_block_coalesce = 0; +int num_page_collect = 0; +int linux_mem_avail; + +int virt_to_phys (vm_address_t addr) +{ + int i; + + for (i = 0; i < MEM_CHUNKS; i++) + { + if (pages_free[i].start <= addr && pages_free[i].end > addr) + return addr - pages_free[i].start + pages_free[i].pstart; + } + debug ("an address not in any chunks."); + abort (); +} + +int phys_to_virt (vm_address_t addr) +{ +#define CHUNK_SIZE(chunk) ((chunk)->end - (chunk)->start) + int i; + + for (i = 0; i < MEM_CHUNKS; i++) + { + if (pages_free[i].pstart <= addr + && pages_free[i].pstart + CHUNK_SIZE (pages_free + i) > addr) + return addr - pages_free[i].pstart + pages_free[i].start; + } + debug ("an address not in any chunks."); + abort (); +} + +/* Initialize the Linux memory allocator. */ +void +linux_kmem_init () +{ + extern mach_port_t priv_host; + int i, j; + + for (i = 0; i < MEM_CHUNKS; i++) + { + error_t err; + + /* Allocate memory. */ + err = vm_dma_buff_alloc (priv_host, mach_task_self (), + MEM_CHUNK_SIZE, &pages_free[i].start, + &pages_free[i].pstart); + if (err) + abort (); + + assert (pages_free[i].start); +// assert ((pages_free[i].start & 0xffff) == 0); + +// /* Sanity check: ensure pages are contiguous and within DMA limits. */ +// for (p = pages, j = 0; j < MEM_CHUNK_SIZE - PAGE_SIZE; j += PAGE_SIZE) +// { +// assert (p->phys_addr < 16 * 1024 * 1024); +// assert (p->phys_addr + PAGE_SIZE +// == ((vm_page_t) p->pageq.next)->phys_addr); +// +// p = (vm_page_t) p->pageq.next; +// } + + pages_free[i].end = pages_free[i].start + MEM_CHUNK_SIZE; + assert (pages_free[i].end <= 16 * 1024 * 1024); + + /* Initialize free page bitmap. */ + pages_free[i].bitmap = 0; + j = MEM_CHUNK_SIZE >> PAGE_SHIFT; + while (--j >= 0) + pages_free[i].bitmap |= 1 << j; + } + + linux_mem_avail = (MEM_CHUNKS * MEM_CHUNK_SIZE) >> PAGE_SHIFT; +} + +/* Return the number by which the page size should be + shifted such that the resulting value is >= SIZE. */ +static unsigned long +get_page_order (int size) +{ + unsigned long order; + + for (order = 0; (PAGE_SIZE << order) < size; order++) + ; + return order; +} + +#ifdef LINUX_DEV_DEBUG +static void +check_page_list (int line) +{ + unsigned size; + struct pagehdr *ph; + struct blkhdr *bh; + + for (ph = memlist; ph; ph = ph->next) + { + if ((int) ph & PAGE_MASK) + panic ("%s:%d: page header not aligned", __FILE__, line); + + size = 0; + bh = (struct blkhdr *) (ph + 1); + while (bh < (struct blkhdr *) ((void *) ph + ph->size)) + { + size += bh->size + sizeof (struct blkhdr); + bh = (void *) (bh + 1) + bh->size; + } + + if (size + sizeof (struct pagehdr) != ph->size) + panic ("%s:%d: memory list destroyed", __FILE__, line); + } +} +#else +#define check_page_list(line) +#endif + +/* Merge adjacent free blocks in the memory list. */ +static void +coalesce_blocks () +{ + struct pagehdr *ph; + struct blkhdr *bh, *bhp, *ebh; + + num_block_coalesce++; + + for (ph = memlist; ph; ph = ph->next) + { + bh = (struct blkhdr *) (ph + 1); + ebh = (struct blkhdr *) ((void *) ph + ph->size); + while (1) + { + /* Skip busy blocks. */ + while (bh < ebh && !bh->free) + bh = (struct blkhdr *) ((void *) (bh + 1) + bh->size); + if (bh == ebh) + break; + + /* Merge adjacent free blocks. */ + while (1) + { + bhp = (struct blkhdr *) ((void *) (bh + 1) + bh->size); + if (bhp == ebh) + { + bh = bhp; + break; + } + if (!bhp->free) + { + bh = (struct blkhdr *) ((void *) (bhp + 1) + bhp->size); + break; + } + bh->size += bhp->size + sizeof (struct blkhdr); + } + } + } +} + +/* Allocate SIZE bytes of memory. + The PRIORITY parameter specifies various flags + such as DMA, atomicity, etc. It is not used by Mach. */ +void * +linux_kmalloc (unsigned int size, int priority) +{ + int order, coalesced = 0; + struct pagehdr *ph; + struct blkhdr *bh, *new_bh; + + if (size < MIN_ALLOC) + size = MIN_ALLOC; + else + size = (size + sizeof (int) - 1) & ~(sizeof (int) - 1); + + assert (size <= (MEM_CHUNK_SIZE + - sizeof (struct pagehdr) + - sizeof (struct blkhdr))); + + mutex_lock (&mem_lock); + +again: + check_page_list (__LINE__); + + /* Walk the page list and find the first free block with size + greater than or equal to the one required. */ + for (ph = memlist; ph; ph = ph->next) + { + bh = (struct blkhdr *) (ph + 1); + while (bh < (struct blkhdr *) ((void *) ph + ph->size)) + { + if (bh->free && bh->size >= size) + { + bh->free = 0; + if (bh->size - size >= MIN_ALLOC + sizeof (struct blkhdr)) + { + /* Split the current block and create a new free block. */ + new_bh = (void *) (bh + 1) + size; + new_bh->free = 1; + new_bh->size = bh->size - size - sizeof (struct blkhdr); + bh->size = size; + } + + check_page_list (__LINE__); + + mutex_unlock (&mem_lock); + return bh + 1; + } + bh = (void *) (bh + 1) + bh->size; + } + } + + check_page_list (__LINE__); + + /* Allocation failed; coalesce free blocks and try again. */ + if (!coalesced) + { + coalesce_blocks (); + coalesced = 1; + goto again; + } + + /* Allocate more pages. */ + order = get_page_order (size + + sizeof (struct pagehdr) + + sizeof (struct blkhdr)); + ph = (struct pagehdr *) __get_free_pages (order, ~0UL); + if (!ph) + { + mutex_unlock (&mem_lock); + return NULL; + } + + ph->size = PAGE_SIZE << order; + ph->next = memlist; + memlist = ph; + bh = (struct blkhdr *) (ph + 1); + bh->free = 0; + bh->size = ph->size - sizeof (struct pagehdr) - sizeof (struct blkhdr); + if (bh->size - size >= MIN_ALLOC + sizeof (struct blkhdr)) + { + new_bh = (void *) (bh + 1) + size; + new_bh->free = 1; + new_bh->size = bh->size - size - sizeof (struct blkhdr); + bh->size = size; + } + + check_page_list (__LINE__); + + mutex_unlock (&mem_lock); + return bh + 1; +} + +/* Free memory P previously allocated by linux_kmalloc. */ +void +linux_kfree (void *p) +{ + struct blkhdr *bh; + struct pagehdr *ph; + + assert (((int) p & (sizeof (int) - 1)) == 0); + + mutex_lock (&mem_lock); + + check_page_list (__LINE__); + + for (ph = memlist; ph; ph = ph->next) + if (p >= (void *) ph && p < (void *) ph + ph->size) + break; + + assert (ph); + + bh = (struct blkhdr *) p - 1; + + assert (!bh->free); + assert (bh->size >= MIN_ALLOC); + assert ((bh->size & (sizeof (int) - 1)) == 0); + + bh->free = 1; + + check_page_list (__LINE__); + + mutex_unlock (&mem_lock); +} + +/* Free any pages that are not in use. + Called by __get_free_pages when pages are running low. */ +static void +collect_kmalloc_pages () +{ + struct blkhdr *bh; + struct pagehdr *ph, **prev_ph; + + check_page_list (__LINE__); + + coalesce_blocks (); + + check_page_list (__LINE__); + + ph = memlist; + prev_ph = &memlist; + while (ph) + { + bh = (struct blkhdr *) (ph + 1); + if (bh->free && (void *) (bh + 1) + bh->size == (void *) ph + ph->size) + { + *prev_ph = ph->next; + free_pages ((unsigned long) ph, get_page_order (ph->size)); + ph = *prev_ph; + } + else + { + prev_ph = &ph->next; + ph = ph->next; + } + } + + check_page_list (__LINE__); +} + +/* Allocate ORDER + 1 number of physically contiguous pages. + PRIORITY and DMA are not used in Mach. + NOTE: mem_lock has been held. + + XXX: This needs to be dynamic. To do that we need to make + the Mach page manipulation routines interrupt safe and they + must provide machine dependant hooks. */ +unsigned long +__get_free_pages (unsigned long order, int dma) +{ + int i, pages_collected = 0; + unsigned bits, off, j, len; + + assert ((PAGE_SIZE << order) <= MEM_CHUNK_SIZE); + + /* Construct bitmap of contiguous pages. */ + bits = 0; + j = 0; + len = 0; + while (len < (PAGE_SIZE << order)) + { + bits |= 1 << j++; + len += PAGE_SIZE; + } + +again: + + /* Search each chunk for the required number of contiguous pages. */ + for (i = 0; i < MEM_CHUNKS; i++) + { + off = 0; + j = bits; + while (MEM_CHUNK_SIZE - off >= (PAGE_SIZE << order)) + { + if ((pages_free[i].bitmap & j) == j) + { + pages_free[i].bitmap &= ~j; + linux_mem_avail -= order + 1; + return pages_free[i].start + off; + } + j <<= 1; + off += PAGE_SIZE; + } + } + + /* Allocation failed; collect kmalloc and buffer pages + and try again. */ + if (!pages_collected) + { + num_page_collect++; + collect_kmalloc_pages (); + pages_collected = 1; + goto again; + } + + printf ("%s:%d: __get_free_pages: ran out of pages\n", __FILE__, __LINE__); + + return 0; +} + +/* Free ORDER + 1 number of physically + contiguous pages starting at address ADDR. */ +void +free_pages (unsigned long addr, unsigned long order) +{ + int i; + unsigned bits, len, j; + + assert ((addr & PAGE_MASK) == 0); + + for (i = 0; i < MEM_CHUNKS; i++) + if (addr >= pages_free[i].start && addr < pages_free[i].end) + break; + + assert (i < MEM_CHUNKS); + + /* Contruct bitmap of contiguous pages. */ + len = 0; + j = 0; + bits = 0; + while (len < (PAGE_SIZE << order)) + { + bits |= 1 << j++; + len += PAGE_SIZE; + } + bits <<= (addr - pages_free[i].start) >> PAGE_SHIFT; + + mutex_lock (&mem_lock); + + assert ((pages_free[i].bitmap & bits) == 0); + + pages_free[i].bitmap |= bits; + linux_mem_avail += order + 1; + mutex_unlock (&mem_lock); +} diff --git a/libddekit/pgtab.c b/libddekit/pgtab.c index 3c39f54f..88273b7c 100644 --- a/libddekit/pgtab.c +++ b/libddekit/pgtab.c @@ -11,47 +11,12 @@ * For this to work, dataspaces must be attached to l4rm regions! */ -#include -#include -#include +#include -#include -#include -#include +#include "ddekit/pgtab.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 ** *****************************/ @@ -64,18 +29,8 @@ static l4lock_t pa_list_lock = L4LOCK_UNLOCKED; */ 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; + extern int virt_to_phys (vm_address_t addr); + return virt_to_phys ((vm_address_t) virtual); } /** @@ -86,32 +41,14 @@ ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virtual) */ 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; + extern int phys_to_virt (vm_address_t addr); + return phys_to_virt (physical); } - - +// TODO int ddekit_pgtab_get_type(const void *virtual) { +#if 0 /* find pgtab object */ struct pgtab_object *p = l4rm_get_userptr(virtual); if (!p) { @@ -121,11 +58,14 @@ int ddekit_pgtab_get_type(const void *virtual) } return p->type; +#endif + return 0; } - +//TODO int ddekit_pgtab_get_size(const void *virtual) { +#if 0 /* find pgtab object */ struct pgtab_object *p = l4rm_get_userptr(virtual); if (!p) { @@ -135,6 +75,8 @@ int ddekit_pgtab_get_size(const void *virtual) } return p->size; +#endif + return 0; } @@ -146,28 +88,6 @@ int ddekit_pgtab_get_size(const void *virtual) */ 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); } @@ -181,39 +101,9 @@ void ddekit_pgtab_clear_region(void *virtual, int type) */ 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); } -- cgit v1.2.3 From b6bc230f90c7ca641f4555647649bdf681a268c1 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 3 Dec 2009 16:46:34 +0100 Subject: Implement panic. --- libddekit/Makefile | 2 +- libddekit/include/ddekit/panic.h | 19 +++++++++++++++++-- libddekit/panic.c | 29 ----------------------------- 3 files changed, 18 insertions(+), 32 deletions(-) delete mode 100644 libddekit/panic.c (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index 59e5c5a9..1203ca38 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -20,7 +20,7 @@ makemode := library libname = libddekit SRCS= condvar.c init.c initcall.c interrupt.c lock.c malloc.c memory.c \ - panic.c pci.c pgtab-old.c pgtab.c printf.c resources.c list.c \ + pci.c pgtab-old.c pgtab.c printf.c resources.c list.c \ thread.c timer.c kmem.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ include/ddekit/initcall.h include/ddekit/debug.h \ diff --git a/libddekit/include/ddekit/panic.h b/libddekit/include/ddekit/panic.h index 1468675f..11c46ebb 100644 --- a/libddekit/include/ddekit/panic.h +++ b/libddekit/include/ddekit/panic.h @@ -3,14 +3,29 @@ /** \defgroup DDEKit_util */ +#include + /** Panic - print error message and enter the kernel debugger. * \ingroup DDEKit_util */ -void ddekit_panic(char *fmt, ...) __attribute__((noreturn)); +#define ddekit_panic(format, ...) do \ +{ \ + char buf[1024]; \ + snprintf (buf, 1024, "%s", format); \ + fprintf (stderr , buf, ## __VA_ARGS__); \ + fflush (stderr); \ + abort (); \ +} while (0) /** Print a debug message. * \ingroup DDEKit_util */ -void ddekit_debug(char *fmt, ...); +#define ddekit_debug(format, ...) do \ +{ \ + char buf[1024]; \ + snprintf (buf, 1024, "%s: %s\n", __func__, format); \ + fprintf (stderr , buf, ## __VA_ARGS__); \ + fflush (stderr); \ +} while (0) #endif diff --git a/libddekit/panic.c b/libddekit/panic.c deleted file mode 100644 index 24ace989..00000000 --- a/libddekit/panic.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include - -#include -#include - -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()"); -} - -- cgit v1.2.3 From 79a5b62aba561e8eb24aa74b789ff71d5c52be5e Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 4 Dec 2009 12:18:26 +0100 Subject: Implement printf and its variant. --- libddekit/init.c | 2 ++ libddekit/printf.c | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 4 deletions(-) (limited to 'libddekit') diff --git a/libddekit/init.c b/libddekit/init.c index 9708ba1d..6bc9d8ff 100644 --- a/libddekit/init.c +++ b/libddekit/init.c @@ -8,7 +8,9 @@ void ddekit_init(void) { extern void linux_kmem_init (); + extern int log_init (); ddekit_init_threads(); linux_kmem_init (); + log_init (); } diff --git a/libddekit/printf.c b/libddekit/printf.c index fb13a0b4..bbd58863 100644 --- a/libddekit/printf.c +++ b/libddekit/printf.c @@ -4,9 +4,12 @@ * \date 2006-03-01 */ -#include +#include +#include -#include +#include "ddekit/printf.h" + +static FILE *output; /** * Log constant string message w/o arguments @@ -15,7 +18,17 @@ */ int ddekit_print(const char *msg) { - return LOG_printf("%s", 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) + fflush (output); + return ret; } /** @@ -42,5 +55,24 @@ int ddekit_printf(const char *fmt, ...) */ int ddekit_vprintf(const char *fmt, va_list va) { - return LOG_vprintf(fmt, va); + char *tmp = NULL; + int ret; + + ret = vasprintf (&tmp, fmt, va); + if (!ret) { + ret = ddekit_print (tmp); + free (tmp); + } + return ret; +} + +int log_init () +{ + char *log_file_name = mktemp ("/tmp/dde_log.XXXXXX"); + output = fopen (log_file_name, "a+"); + if (!output) { + error (0, errno, "open %s", log_file_name); + return -1; + } + return 0; } -- cgit v1.2.3 From 85f31e4301efbb0721dc1de148738f94cb73fe8f Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 5 Dec 2009 02:53:15 +0100 Subject: Implementation of interrupt. --- libddekit/include/ddekit/interrupt.h | 4 +- libddekit/interrupt.c | 127 ++++++++++++++++++----------------- 2 files changed, 67 insertions(+), 64 deletions(-) (limited to 'libddekit') diff --git a/libddekit/include/ddekit/interrupt.h b/libddekit/include/ddekit/interrupt.h index bbabedb2..3f789210 100644 --- a/libddekit/include/ddekit/interrupt.h +++ b/libddekit/include/ddekit/interrupt.h @@ -12,9 +12,9 @@ #ifndef _ddekit_interrupt_h #define _ddekit_interrupt_h -#include +#include "ddekit/thread.h" -#define DDEKIT_IRQ_PRIO 0x11 +#define DDEKIT_IRQ_PRIO 2 /** * Attach to hardware interrupt diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index 557611a6..142659ff 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -8,15 +8,7 @@ * FIXME use consume flag to indicate IRQ was handled */ -#include -#include -#include -#include -#include - -#include -#include -#include +#include "ddekit/interrupt.h" #include @@ -44,58 +36,57 @@ struct intloop_params static struct { int handle_irq; /* nested irq disable count */ - ddekit_sem_t *irqsem; /* synch semaphore */ + ddekit_lock_t *irqlock; ddekit_thread_t *irq_thread; /* thread ID for detaching from IRQ later on */ - omega0_irqdesc_t irq_desc; /* Omega0-style IRQ descriptor */ + boolean_t thread_exit; + thread_t mach_thread; } 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); + // TODO we can remove the port for delivery of interrupt explicitly, + // though it cannot cause any harm even if we don't remove it. } -L4THREAD_EXIT_FN_STATIC(exit_fn, ddekit_irq_exit_fn); - - /** * Interrupt service loop * */ static void intloop(void *arg) { + kern_return_t ret; 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) { + mach_port_t delivery_port; + int my_index; + + my_index = params->irq; + ddekit_irq_ctrl[my_index]->mach_thread = mach_thread_self (); + ret = thread_priority (mach_thread_self (), DDEKIT_IRQ_PRIO, 0); + if (ret) + error (0, ret, "thread_priority"); + + // TODO I should give another parameter to show whether + // the interrupt can be shared. + ret = device_intr_notify (master_device, dev->irq, + dev->dev_id, delivery_port, + MACH_MSG_TYPE_MAKE_SEND); + if (!ret) { /* inform thread creator of error */ /* XXX does omega0 error code have any meaning to DDEKit users? */ - params->start_err = o0handle; + params->start_err = ret; ddekit_sem_up(params->started); - return; + return NULL; } +#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 */ @@ -105,27 +96,21 @@ static void intloop(void *arg) 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); + int irq_server (mach_msg_header_t *inp, mach_msg_header_t *outp) { + mach_irq_notification_t *irq_header = (mach_irq_notification_t *) inp; - LOGd(DEBUG_INTERRUPTS, "received irq 0x%X", err - 1); + if (inp->msgh_id != MACH_NOTIFY_IRQ) + return 0; - /* unmask only the first time */ - req.s.unmask = 0; + /* It's an interrupt not for us. It shouldn't happen. */ + if (irq_header->irq != params->irq) { + LOG("We get interrupt %d, %d is expected", + irq_header->irq, params->irq); + return 1; + } /* only call registered handler function, if IRQ is not disabled */ - ddekit_sem_down(ddekit_irq_ctrl[my_index].irqsem); + ddekit_lock_lock (&ddekit_irq_ctrl[my_index].irqlock); if (ddekit_irq_ctrl[my_index].handle_irq > 0) { LOGd(DEBUG_INTERRUPTS, "IRQ %x, handler %p", my_index,params->handler); params->handler(params->priv); @@ -133,9 +118,18 @@ static void intloop(void *arg) 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"); + // ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY; + + if (ddekit_irq_ctrl[irq].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 (int_server, 0, delivery_port); } @@ -164,6 +158,7 @@ ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, 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; @@ -175,6 +170,7 @@ ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, /* construct name */ snprintf(thread_name, 10, "irq%02X", irq); + /* allocate irq */ /* create interrupt loop thread */ thread = ddekit_thread_create(intloop, params, thread_name); if (!thread) { @@ -182,9 +178,11 @@ ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, return NULL; } + // TODO can ddekit really work for shared irq? 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); + ddekit_lock_init_unlocked (&ddekit_irq_ctrl[irq].irqlock); + ddekit_irq_ctrl[irq].thread_exit = FALSE; /* wait for intloop initialization result */ @@ -205,25 +203,30 @@ ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, void ddekit_interrupt_detach(int irq) { ddekit_interrupt_disable(irq); - ddekit_thread_terminate(ddekit_irq_ctrl[irq].irq_thread); + ddekit_lock_lock (&ddekit_irq_ctrl[irq].irqlock); + ddekit_irq_ctrl[irq].thread_exit = TRUE; + ddekit_lock_unlock (&ddekit_irq_ctrl[irq].irqlock); + + /* I hope this ugly trick can work. */ + thread_abort (ddekit_irq_ctrl[irq].mach_thread); } void ddekit_interrupt_disable(int irq) { - if (ddekit_irq_ctrl[irq].irqsem) { - ddekit_sem_down(ddekit_irq_ctrl[irq].irqsem); + if (ddekit_irq_ctrl[irq].irqlock) { + ddekit_lock_lock (&ddekit_irq_ctrl[irq].irqlock); --ddekit_irq_ctrl[irq].handle_irq; - ddekit_sem_up(ddekit_irq_ctrl[irq].irqsem); + ddekit_lock_unlock (&ddekit_irq_ctrl[irq].irqlock); } } void ddekit_interrupt_enable(int irq) { - if (ddekit_irq_ctrl[irq].irqsem) { - ddekit_sem_down(ddekit_irq_ctrl[irq].irqsem); + if (ddekit_irq_ctrl[irq].irqlock) { + ddekit_lock_lock (&ddekit_irq_ctrl[irq].irqlock); ++ddekit_irq_ctrl[irq].handle_irq; - ddekit_sem_up(ddekit_irq_ctrl[irq].irqsem); + ddekit_lock_unlock (&ddekit_irq_ctrl[irq].irqlock); } } -- cgit v1.2.3 From d73efeeaba75cbdc5b3c23037f1e9f9f82d2d0c9 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 5 Dec 2009 03:27:51 +0100 Subject: Fix a bug. The interrupt handler can only been attached to the same irq once. --- libddekit/interrupt.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'libddekit') diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index 142659ff..6a8b3fd8 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -154,6 +154,10 @@ ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, 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; @@ -178,7 +182,6 @@ ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, return NULL; } - // TODO can ddekit really work for shared irq? ddekit_irq_ctrl[irq].handle_irq = 1; /* IRQ nesting level is initially 1 */ ddekit_irq_ctrl[irq].irq_thread = thread; ddekit_lock_init_unlocked (&ddekit_irq_ctrl[irq].irqlock); @@ -204,11 +207,16 @@ void ddekit_interrupt_detach(int irq) { ddekit_interrupt_disable(irq); ddekit_lock_lock (&ddekit_irq_ctrl[irq].irqlock); - ddekit_irq_ctrl[irq].thread_exit = TRUE; + 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); - - /* I hope this ugly trick can work. */ - thread_abort (ddekit_irq_ctrl[irq].mach_thread); } -- cgit v1.2.3 From b4bffcfcdf3ab7a55d664e9aa5907f88da503f38 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 6 Dec 2009 05:14:54 +0100 Subject: The code can be compiled now. --- libddekit/Makefile | 11 +- libddekit/condvar.c | 4 +- libddekit/device.defs | 204 ++++++++++ libddekit/include/Makefile | 9 - libddekit/include/ddekit/assert.h | 4 +- libddekit/include/ddekit/condvar.h | 1 + libddekit/include/ddekit/initcall.h | 42 -- libddekit/include/ddekit/thread.h | 2 + libddekit/init.c | 3 + libddekit/initcall.c | 8 - libddekit/interrupt.c | 63 ++- libddekit/kmem.c | 5 +- libddekit/list.c | 4 +- libddekit/lock.c | 3 +- libddekit/mach.defs | 779 ++++++++++++++++++++++++++++++++++++ libddekit/malloc.c | 3 + libddekit/memory.c | 5 +- libddekit/pci.c | 33 +- libddekit/printf.c | 3 + libddekit/thread.c | 68 ++-- libddekit/timer.c | 7 +- libddekit/vm_param.h | 7 + 22 files changed, 1132 insertions(+), 136 deletions(-) create mode 100644 libddekit/device.defs delete mode 100644 libddekit/include/Makefile delete mode 100644 libddekit/include/ddekit/initcall.h delete mode 100644 libddekit/initcall.c create mode 100644 libddekit/mach.defs create mode 100644 libddekit/vm_param.h (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index 1203ca38..67a3b193 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -19,22 +19,22 @@ dir := libddekit makemode := library libname = libddekit -SRCS= condvar.c init.c initcall.c interrupt.c lock.c malloc.c memory.c \ - pci.c pgtab-old.c pgtab.c printf.c resources.c list.c \ +SRCS= condvar.c init.c interrupt.c lock.c malloc.c memory.c \ + pci.c pgtab.c printf.c resources.c list.c \ thread.c timer.c kmem.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ - include/ddekit/initcall.h include/ddekit/debug.h \ + include/ddekit/semaphore.h include/ddekit/debug.h \ include/ddekit/inline.h include/ddekit/panic.h \ include/ddekit/thread.h include/ddekit/types.h \ include/ddekit/pgtab.h include/ddekit/printf.h \ include/ddekit/pci.h include/ddekit/assert.h \ include/ddekit/interrupt.h include/ddekit/resources.h \ include/ddekit/memory.h include/ddekit/timer.h \ - include/ddekit/semaphore.h include/dde.h \ + include/dde.h \ config.h list.h installhdrs = -MIGSTUBS = +MIGSTUBS = deviceUser.o machUser.o OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS)) HURDLIBS = threads ports @@ -44,3 +44,4 @@ MIGCOMSFLAGS = -prefix dde_ include ../Makeconf LDFLAGS += -lpciaccess +CFLAGS += -Iinclude -Iinclude/ddekit diff --git a/libddekit/condvar.c b/libddekit/condvar.c index 96e28c07..bbd49417 100644 --- a/libddekit/condvar.c +++ b/libddekit/condvar.c @@ -13,12 +13,12 @@ struct ddekit_condvar { }; ddekit_condvar_t *ddekit_condvar_init() { - ddekit_condvar_t *cvp; + struct condition *cvp; cvp = condition_alloc (); condition_init (cvp); - return cvp; + return (ddekit_condvar_t *) cvp; } void ddekit_condvar_wait(ddekit_condvar_t *cvp, ddekit_lock_t *mp) { diff --git a/libddekit/device.defs b/libddekit/device.defs new file mode 100644 index 00000000..6a73853a --- /dev/null +++ b/libddekit/device.defs @@ -0,0 +1,204 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: device/device.defs + * Author: Douglas Orr + * Feb 10, 1988 + * Abstract: + * Mach device support. Mach devices are accessed through + * block and character device interfaces to the kernel. + */ + +#ifdef MACH_KERNEL +simport ; /* for obsolete routines */ +#endif + +subsystem +#if KERNEL_SERVER + KernelServer +#endif + device 2800; + +#include +#include +#include + +serverprefix ds_; + +type pci_config_data_t = array[*:4] of char; +type reply_port_t = MACH_MSG_TYPE_MAKE_SEND_ONCE | polymorphic + ctype: mach_port_t; + +routine device_open( + master_port : mach_port_t; + sreplyport reply_port : reply_port_t; + mode : dev_mode_t; + name : dev_name_t; + out device : device_t + ); + +routine device_close( + device : device_t + ); + +routine device_write( + device : device_t; + sreplyport reply_port : reply_port_t; + in mode : dev_mode_t; + in recnum : recnum_t; + in data : io_buf_ptr_t; + out bytes_written : int + ); + +routine device_write_inband( + device : device_t; + sreplyport reply_port : reply_port_t; + in mode : dev_mode_t; + in recnum : recnum_t; + in data : io_buf_ptr_inband_t; + out bytes_written : int + ); + +routine device_read( + device : device_t; + sreplyport reply_port : reply_port_t; + in mode : dev_mode_t; + in recnum : recnum_t; + in bytes_wanted : int; + out data : io_buf_ptr_t + ); + +routine device_read_inband( + device : device_t; + sreplyport reply_port : reply_port_t; + in mode : dev_mode_t; + in recnum : recnum_t; + in bytes_wanted : int; + out data : io_buf_ptr_inband_t + ); + +/* obsolete */ +routine xxx_device_set_status( + device : device_t; + in flavor : dev_flavor_t; + in status : dev_status_t, IsLong + ); + +/* obsolete */ +routine xxx_device_get_status( + device : device_t; + in flavor : dev_flavor_t; + out status : dev_status_t, IsLong + ); + +/* obsolete */ +routine xxx_device_set_filter( + device : device_t; + in receive_port : mach_port_send_t; + in priority : int; + in filter : filter_array_t, IsLong + ); + +routine device_map( + device : device_t; + in prot : vm_prot_t; + in offset : vm_offset_t; + in size : vm_size_t; + out pager : memory_object_t; + in unmap : int + ); + +routine device_set_status( + device : device_t; + in flavor : dev_flavor_t; + in status : dev_status_t + ); + +routine device_get_status( + device : device_t; + in flavor : dev_flavor_t; + out status : dev_status_t, CountInOut + ); + +routine device_set_filter( + device : device_t; + in receive_port : mach_port_send_t; + in priority : int; + in filter : filter_array_t + ); + +routine device_intr_notify( + master_port : mach_port_t; + in irq : int; + in id : int; + in receive_port : mach_port_send_t + ); + +/* + * Test whether IPC devices exist. + */ +routine pci_present( + master_port : mach_port_t); + +/* + * Find the specified PCI device. + */ +routine pci_find_device( + master_port : mach_port_t; + vendor : short; + device_id : short; + index : short; + out bus : char; + out device_fn : char); + +/* + * Read the configuration space of a IPC device. + */ +routine pci_read_config( + master_port : mach_port_t; + bus : char; + device_fn : char; + where : char; + bytes_wanted : int; + out result : pci_config_data_t); + +/* + * Write the configuration space of a IPC device. + */ +routine pci_write_config( + master_port : mach_port_t; + bus : char; + device_fn : char; + where : char; + data : pci_config_data_t); + +/* + * enable/disable the specified irq. + */ +routine device_irq_enable( + master_port : mach_port_t; + irq : int; + status : char); diff --git a/libddekit/include/Makefile b/libddekit/include/Makefile deleted file mode 100644 index 8d31023f..00000000 --- a/libddekit/include/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -PKGDIR ?= .. -L4DIR ?= $(PKGDIR)/../.. - -# All haeder files found in this directory tree will be automatically -# installed in a way that they can be included with -# #include later. -# No need to list them in this Makefile. - -include $(L4DIR)/mk/include.mk diff --git a/libddekit/include/ddekit/assert.h b/libddekit/include/ddekit/assert.h index 5d572b49..5d593662 100644 --- a/libddekit/include/ddekit/assert.h +++ b/libddekit/include/ddekit/assert.h @@ -1,8 +1,8 @@ #ifndef _ddekit_assert_h #define _ddekit_assert_h -#include -#include +#include "ddekit/printf.h" +#include "ddekit/panic.h" /** \file ddekit/assert.h */ diff --git a/libddekit/include/ddekit/condvar.h b/libddekit/include/ddekit/condvar.h index ba87358d..129a718d 100644 --- a/libddekit/include/ddekit/condvar.h +++ b/libddekit/include/ddekit/condvar.h @@ -2,6 +2,7 @@ #define _ddekit_condvar_h /** \file ddekit/condvar.h */ +#include "ddekit/lock.h" struct ddekit_condvar; typedef struct ddekit_condvar ddekit_condvar_t; diff --git a/libddekit/include/ddekit/initcall.h b/libddekit/include/ddekit/initcall.h deleted file mode 100644 index b503cc6a..00000000 --- a/libddekit/include/ddekit/initcall.h +++ /dev/null @@ -1,42 +0,0 @@ -#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) \ - static 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/include/ddekit/thread.h b/libddekit/include/ddekit/thread.h index 6e505818..8ed52013 100644 --- a/libddekit/include/ddekit/thread.h +++ b/libddekit/include/ddekit/thread.h @@ -3,6 +3,8 @@ /** \defgroup DDEKit_threads */ +#include "ddekit/lock.h" + struct ddekit_thread; typedef struct ddekit_thread ddekit_thread_t; diff --git a/libddekit/init.c b/libddekit/init.c index 6bc9d8ff..9114ff46 100644 --- a/libddekit/init.c +++ b/libddekit/init.c @@ -9,8 +9,11 @@ void ddekit_init(void) { extern void linux_kmem_init (); extern int log_init (); + extern void interrupt_init (); + ddekit_init_threads(); linux_kmem_init (); log_init (); + interrupt_init (); } diff --git a/libddekit/initcall.c b/libddekit/initcall.c deleted file mode 100644 index 49e1fec1..00000000 --- a/libddekit/initcall.c +++ /dev/null @@ -1,8 +0,0 @@ -#include - -#include - -void ddekit_do_initcalls() { - crt0_dde_construction(); -} - diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index 6a8b3fd8..5a778f9b 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -8,9 +8,17 @@ * FIXME use consume flag to indicate IRQ was handled */ +#include +#include +#include +#include + #include "ddekit/interrupt.h" +#include "ddekit/semaphore.h" +#include "ddekit/printf.h" +#include "ddekit/memory.h" -#include +#include "device_U.h" #define DEBUG_INTERRUPTS 0 @@ -18,6 +26,15 @@ #define BLOCK_IRQ 0 +#define MACH_NOTIFY_IRQ 100 + +typedef struct +{ + mach_msg_header_t irq_header; + mach_msg_type_t irq_type; + int irq; +} mach_irq_notification_t; + /* * Internal type for interrupt loop parameters */ @@ -35,19 +52,14 @@ struct intloop_params static struct { - int handle_irq; /* nested irq disable count */ - ddekit_lock_t *irqlock; + int handle_irq; /* nested irq disable count */ + ddekit_lock_t irqlock; 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 void ddekit_irq_exit_fn(l4thread_t thread, void *data) -{ - // TODO we can remove the port for delivery of interrupt explicitly, - // though it cannot cause any harm even if we don't remove it. -} +static mach_port_t master_device; /** * Interrupt service loop @@ -57,26 +69,25 @@ static void intloop(void *arg) { kern_return_t ret; struct intloop_params *params = arg; - mach_port_t delivery_port; + mach_port_t delivery_port = mach_reply_port (); int my_index; my_index = params->irq; - ddekit_irq_ctrl[my_index]->mach_thread = mach_thread_self (); + ddekit_irq_ctrl[my_index].mach_thread = mach_thread_self (); ret = thread_priority (mach_thread_self (), DDEKIT_IRQ_PRIO, 0); if (ret) error (0, ret, "thread_priority"); // TODO I should give another parameter to show whether // the interrupt can be shared. - ret = device_intr_notify (master_device, dev->irq, - dev->dev_id, delivery_port, + ret = device_intr_notify (master_device, params->irq, + 0, delivery_port, MACH_MSG_TYPE_MAKE_SEND); 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); - return NULL; } #if 0 @@ -104,23 +115,25 @@ static void intloop(void *arg) /* It's an interrupt not for us. It shouldn't happen. */ if (irq_header->irq != params->irq) { - LOG("We get interrupt %d, %d is expected", - irq_header->irq, params->irq); + ddekit_printf ("We get interrupt %d, %d is expected", + irq_header->irq, params->irq); return 1; } /* only call registered handler function, if IRQ is not disabled */ ddekit_lock_lock (&ddekit_irq_ctrl[my_index].irqlock); if (ddekit_irq_ctrl[my_index].handle_irq > 0) { - LOGd(DEBUG_INTERRUPTS, "IRQ %x, handler %p", my_index,params->handler); + ddekit_printf ("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_printf ("not handling IRQ %x, because it is disabled.", + my_index); // ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY; - if (ddekit_irq_ctrl[irq].thread_exit) { + if (ddekit_irq_ctrl[my_index].thread_exit) { ddekit_lock_unlock (&ddekit_irq_ctrl[my_index].irqlock); ddekit_thread_exit(); return 1; @@ -129,7 +142,7 @@ static void intloop(void *arg) return 1; } - mach_msg_server (int_server, 0, delivery_port); + mach_msg_server (irq_server, 0, delivery_port); } @@ -238,3 +251,13 @@ void ddekit_interrupt_enable(int irq) ddekit_lock_unlock (&ddekit_irq_ctrl[irq].irqlock); } } + +void interrupt_init () +{ + + error_t err; + + err = get_privileged_ports (0, &master_device); + if (err) + error (1, err, "get_privileged_ports"); +} diff --git a/libddekit/kmem.c b/libddekit/kmem.c index 4769190e..2e6f7340 100644 --- a/libddekit/kmem.c +++ b/libddekit/kmem.c @@ -28,9 +28,12 @@ #include #include -#include "util.h" #include "vm_param.h" +#include "ddekit/panic.h" + +#define debug ddekit_debug + extern int printf (const char *, ...); /* Amount of memory to reserve for Linux memory allocator. diff --git a/libddekit/list.c b/libddekit/list.c index 992ea9ad..4f163584 100644 --- a/libddekit/list.c +++ b/libddekit/list.c @@ -48,7 +48,7 @@ struct list *remove_entry_head (struct list *head) { struct list *entry = head->next; - if (EMPTY_ENTRY (entry)) + if (EMPTY_LIST (entry)) return NULL; remove_entry (entry); @@ -59,7 +59,7 @@ struct list *remove_entry_end (struct list *head) { struct list *entry = head->prev; - if (EMPTY_ENTRY (entry)) + if (EMPTY_LIST (entry)) return NULL; remove_entry (entry); diff --git a/libddekit/lock.c b/libddekit/lock.c index bf643e65..4c4cff01 100644 --- a/libddekit/lock.c +++ b/libddekit/lock.c @@ -1,6 +1,7 @@ #include #include "ddekit/lock.h" +#include "ddekit/memory.h" #define DDEKIT_DEBUG_LOCKS 0 @@ -48,6 +49,6 @@ 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)->holder; + return (int) (*mtx)->helder; } diff --git a/libddekit/mach.defs b/libddekit/mach.defs new file mode 100644 index 00000000..764bd451 --- /dev/null +++ b/libddekit/mach.defs @@ -0,0 +1,779 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University. + * Copyright (c) 1993,1994 The University of Utah and + * the Computer Systems Laboratory (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF + * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY + * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF + * THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Matchmaker definitions file for Mach kernel interface. + */ + +#ifdef MACH_KERNEL +simport ; /* for obsolete routines */ +#endif /* MACH_KERNEL */ + +subsystem +#if KERNEL_USER + KernelUser +#endif /* KERNEL_USER */ +#if KERNEL_SERVER + KernelServer +#endif /* KERNEL_SERVER */ + mach 2000; + +#ifdef KERNEL_USER +userprefix r_; +#endif /* KERNEL_USER */ + +#include +#include + +skip; /* old port_allocate */ +skip; /* old port_deallocate */ +skip; /* old port_enable */ +skip; /* old port_disable */ +skip; /* old port_select */ +skip; /* old port_set_backlog */ +skip; /* old port_status */ + +/* + * Create a new task with an empty set of IPC rights, + * and having an address space constructed from the + * target task (or empty, if inherit_memory is FALSE). + */ +routine task_create( + target_task : task_t; + inherit_memory : boolean_t; + out child_task : task_t); + +/* + * Destroy the target task, causing all of its threads + * to be destroyed, all of its IPC rights to be deallocated, + * and all of its address space to be deallocated. + */ +routine task_terminate( + target_task : task_t); + +/* + * Get user-level handler entry points for all + * emulated system calls. + */ +routine task_get_emulation_vector( + task : task_t; + out vector_start : int; + out emulation_vector: emulation_vector_t); + +/* + * Establish user-level handlers for the specified + * system calls. Non-emulated system calls are specified + * with emulation_vector[i] == EML_ROUTINE_NULL. + */ +routine task_set_emulation_vector( + task : task_t; + vector_start : int; + emulation_vector: emulation_vector_t); + + +/* + * Returns the set of threads belonging to the target task. + */ +routine task_threads( + target_task : task_t; + out thread_list : thread_array_t); + +/* + * Returns information about the target task. + */ +routine task_info( + target_task : task_t; + flavor : int; + out task_info_out : task_info_t, CountInOut); + + +skip; /* old task_status */ +skip; /* old task_set_notify */ +skip; /* old thread_create */ + +/* + * Destroy the target thread. + */ +routine thread_terminate( + target_thread : thread_t); + +/* + * Return the selected state information for the target + * thread. If the thread is currently executing, the results + * may be stale. [Flavor THREAD_STATE_FLAVOR_LIST provides a + * list of valid flavors for the target thread.] + */ +routine thread_get_state( + target_thread : thread_t; + flavor : int; + out old_state : thread_state_t, CountInOut); + +/* + * Set the selected state information for the target thread. + * If the thread is currently executing, the state change + * may be ill-defined. + */ +routine thread_set_state( + target_thread : thread_t; + flavor : int; + new_state : thread_state_t); + +/* + * Returns information about the target thread. + */ +routine thread_info( + target_thread : thread_t; + flavor : int; + out thread_info_out : thread_info_t, CountInOut); + +skip; /* old thread_mutate */ + +/* + * Allocate zero-filled memory in the address space + * of the target task, either at the specified address, + * or wherever space can be found (if anywhere is TRUE), + * of the specified size. The address at which the + * allocation actually took place is returned. + */ +#ifdef EMULATOR +skip; /* the emulator redefines vm_allocate using vm_map */ +#else /* EMULATOR */ +routine vm_allocate( + target_task : vm_task_t; + inout address : vm_address_t; + size : vm_size_t; + anywhere : boolean_t); +#endif /* EMULATOR */ + +skip; /* old vm_allocate_with_pager */ + +/* + * Deallocate the specified range from the virtual + * address space of the target task. + */ +routine vm_deallocate( + target_task : vm_task_t; + address : vm_address_t; + size : vm_size_t); + +/* + * Set the current or maximum protection attribute + * for the specified range of the virtual address + * space of the target task. The current protection + * limits the memory access rights of threads within + * the task; the maximum protection limits the accesses + * that may be given in the current protection. + * Protections are specified as a set of {read, write, execute} + * *permissions*. + */ +routine vm_protect( + target_task : vm_task_t; + address : vm_address_t; + size : vm_size_t; + set_maximum : boolean_t; + new_protection : vm_prot_t); + +/* + * Set the inheritance attribute for the specified range + * of the virtual address space of the target task. + * The inheritance value is one of {none, copy, share}, and + * specifies how the child address space should acquire + * this memory at the time of a task_create call. + */ +routine vm_inherit( + target_task : vm_task_t; + address : vm_address_t; + size : vm_size_t; + new_inheritance : vm_inherit_t); + +/* + * Returns the contents of the specified range of the + * virtual address space of the target task. [The + * range must be aligned on a virtual page boundary, + * and must be a multiple of pages in extent. The + * protection on the specified range must permit reading.] + */ +routine vm_read( + target_task : vm_task_t; + address : vm_address_t; + size : vm_size_t; + out data : pointer_t); + +/* + * Writes the contents of the specified range of the + * virtual address space of the target task. [The + * range must be aligned on a virtual page boundary, + * and must be a multiple of pages in extent. The + * protection on the specified range must permit writing.] + */ +routine vm_write( + target_task : vm_task_t; + address : vm_address_t; + data : pointer_t); + +/* + * Copy the contents of the source range of the virtual + * address space of the target task to the destination + * range in that same address space. [Both of the + * ranges must be aligned on a virtual page boundary, + * and must be multiples of pages in extent. The + * protection on the source range must permit reading, + * and the protection on the destination range must + * permit writing.] + */ +routine vm_copy( + target_task : vm_task_t; + source_address : vm_address_t; + size : vm_size_t; + dest_address : vm_address_t); + +/* + * Returns information about the contents of the virtual + * address space of the target task at the specified + * address. The returned protection, inheritance, sharing + * and memory object values apply to the entire range described + * by the address range returned; the memory object offset + * corresponds to the beginning of the address range. + * [If the specified address is not allocated, the next + * highest address range is described. If no addresses beyond + * the one specified are allocated, the call returns KERN_NO_SPACE.] + */ +routine vm_region( + target_task : vm_task_t; + inout address : vm_address_t; + out size : vm_size_t; + out protection : vm_prot_t; + out max_protection : vm_prot_t; + out inheritance : vm_inherit_t; + out is_shared : boolean_t; + /* avoid out-translation of the argument */ + out object_name : memory_object_name_t = + MACH_MSG_TYPE_MOVE_SEND + ctype: mach_port_t; + out offset : vm_offset_t); + +/* + * Return virtual memory statistics for the host + * on which the target task resides. [Note that the + * statistics are not specific to the target task.] + */ +routine vm_statistics( + target_task : vm_task_t; + out vm_stats : vm_statistics_data_t); + +skip; /* old task_by_u*x_pid */ +skip; /* old vm_pageable */ + +/* + * Stash a handful of ports for the target task; child + * tasks inherit this stash at task_create time. + */ +routine mach_ports_register( + target_task : task_t; + init_port_set : mach_port_array_t = + ^array[] of mach_port_t); + +/* + * Retrieve the stashed ports for the target task. + */ +routine mach_ports_lookup( + target_task : task_t; + out init_port_set : mach_port_array_t = + ^array[] of mach_port_t); + +skip; /* old u*x_pid */ +skip; /* old netipc_listen */ +skip; /* old netipc_ignore */ + +/* + * Provide the data contents of a range of the given memory + * object, with the access restriction specified. [Only + * whole virtual pages of data can be accepted; partial pages + * will be discarded. Data should be provided on request, but + * may be provided in advance as desired. When data already + * held by this kernel is provided again, the new data is ignored. + * The access restriction is the subset of {read, write, execute} + * which are prohibited. The kernel may not provide any data (or + * protection) consistency among pages with different virtual page + * alignments within the same object.] + */ +simpleroutine memory_object_data_provided( + memory_control : memory_object_control_t; + offset : vm_offset_t; + data : pointer_t; + lock_value : vm_prot_t); + +/* + * Indicate that a range of the given temporary memory object does + * not exist, and that the backing memory object should be used + * instead (or zero-fill memory be used, if no backing object exists). + * [This call is intended for use only by the default memory manager. + * It should not be used to indicate a real error -- + * memory_object_data_error should be used for that purpose.] + */ +simpleroutine memory_object_data_unavailable( + memory_control : memory_object_control_t; + offset : vm_offset_t; + size : vm_size_t); + +/* + * Retrieves the attributes currently associated with + * a memory object. + */ +routine memory_object_get_attributes( + memory_control : memory_object_control_t; + out object_ready : boolean_t; + out may_cache : boolean_t; + out copy_strategy : memory_object_copy_strategy_t); + +/* + * Sets the default memory manager, the port to which + * newly-created temporary memory objects are delivered. + * [See (memory_object_default)memory_object_create.] + * The old memory manager port is returned. + */ +routine vm_set_default_memory_manager( + host_priv : host_priv_t; + inout default_manager : mach_port_make_send_t); + +skip; /* old pager_flush_request */ + +/* + * Control use of the data associated with the given + * memory object. For each page in the given range, + * perform the following operations, in order: + * 1) restrict access to the page (disallow + * forms specified by "prot"); + * 2) write back modifications (if "should_return" + * is RETURN_DIRTY and the page is dirty, or + * "should_return" is RETURN_ALL and the page + * is either dirty or precious); and, + * 3) flush the cached copy (if "should_flush" + * is asserted). + * The set of pages is defined by a starting offset + * ("offset") and size ("size"). Only pages with the + * same page alignment as the starting offset are + * considered. + * + * A single acknowledgement is sent (to the "reply_to" + * port) when these actions are complete. + * + * There are two versions of this routine because IPC distinguishes + * between booleans and integers (a 2-valued integer is NOT a + * boolean). The new routine is backwards compatible at the C + * language interface. + */ +simpleroutine xxx_memory_object_lock_request( + memory_control : memory_object_control_t; + offset : vm_offset_t; + size : vm_size_t; + should_clean : boolean_t; + should_flush : boolean_t; + lock_value : vm_prot_t; + reply_to : mach_port_t = + MACH_MSG_TYPE_MAKE_SEND_ONCE|polymorphic); + + +simpleroutine memory_object_lock_request( + memory_control : memory_object_control_t; + offset : vm_offset_t; + size : vm_size_t; + should_return : memory_object_return_t; + should_flush : boolean_t; + lock_value : vm_prot_t; + reply_to : mach_port_t = + MACH_MSG_TYPE_MAKE_SEND_ONCE|polymorphic); + +/* obsolete */ +routine xxx_task_get_emulation_vector( + task : task_t; + out vector_start : int; + out emulation_vector: xxx_emulation_vector_t, IsLong); + +/* obsolete */ +routine xxx_task_set_emulation_vector( + task : task_t; + vector_start : int; + emulation_vector: xxx_emulation_vector_t, IsLong); + +/* + * Returns information about the host on which the + * target object resides. [This object may be + * a task, thread, or memory_object_control port.] + */ +routine xxx_host_info( + target_task : mach_port_t; + out info : machine_info_data_t); + +/* + * Returns information about a particular processor on + * the host on which the target task resides. + */ +routine xxx_slot_info( + target_task : task_t; + slot : int; + out info : machine_slot_data_t); + +/* + * Performs control operations (currently only + * turning off or on) on a particular processor on + * the host on which the target task resides. + */ +routine xxx_cpu_control( + target_task : task_t; + cpu : int; + running : boolean_t); + +skip; /* old thread_statistics */ +skip; /* old task_statistics */ +skip; /* old netport_init */ +skip; /* old netport_enter */ +skip; /* old netport_remove */ +skip; /* old thread_set_priority */ + +/* + * Increment the suspend count for the target task. + * No threads within a task may run when the suspend + * count for that task is non-zero. + */ +routine task_suspend( + target_task : task_t); + +/* + * Decrement the suspend count for the target task, + * if the count is currently non-zero. If the resulting + * suspend count is zero, then threads within the task + * that also have non-zero suspend counts may execute. + */ +routine task_resume( + target_task : task_t); + +/* + * Returns the current value of the selected special port + * associated with the target task. + */ +routine task_get_special_port( + task : task_t; + which_port : int; + out special_port : mach_port_t); + +/* + * Set one of the special ports associated with the + * target task. + */ +routine task_set_special_port( + task : task_t; + which_port : int; + special_port : mach_port_t); + +/* obsolete */ +routine xxx_task_info( + target_task : task_t; + flavor : int; + out task_info_out : task_info_t, IsLong); + + +/* + * Create a new thread within the target task, returning + * the port representing that new thread. The + * initial execution state of the thread is undefined. + */ +routine thread_create( + parent_task : task_t; + out child_thread : thread_t); + +/* + * Increment the suspend count for the target thread. + * Once this call has completed, the thread will not + * execute any further user or meta- instructions. + * Once suspended, a thread may not execute again until + * its suspend count is zero, and the suspend count + * for its task is also zero. + */ +routine thread_suspend( + target_thread : thread_t); + +/* + * Decrement the suspend count for the target thread, + * if that count is not already zero. + */ +routine thread_resume( + target_thread : thread_t); + +/* + * Cause any user or meta- instructions currently being + * executed by the target thread to be aborted. [Meta- + * instructions consist of the basic traps for IPC + * (e.g., msg_send, msg_receive) and self-identification + * (e.g., task_self, thread_self, thread_reply). Calls + * described by MiG interfaces are not meta-instructions + * themselves.] + */ +routine thread_abort( + target_thread : thread_t); + +/* obsolete */ +routine xxx_thread_get_state( + target_thread : thread_t; + flavor : int; + out old_state : thread_state_t, IsLong); + +/* obsolete */ +routine xxx_thread_set_state( + target_thread : thread_t; + flavor : int; + new_state : thread_state_t, IsLong); + +/* + * Returns the current value of the selected special port + * associated with the target thread. + */ +routine thread_get_special_port( + thread : thread_t; + which_port : int; + out special_port : mach_port_t); + +/* + * Set one of the special ports associated with the + * target thread. + */ +routine thread_set_special_port( + thread : thread_t; + which_port : int; + special_port : mach_port_t); + +/* obsolete */ +routine xxx_thread_info( + target_thread : thread_t; + flavor : int; + out thread_info_out : thread_info_t, IsLong); + +/* + * Establish a user-level handler for the specified + * system call. + */ +routine task_set_emulation( + target_port : task_t; + routine_entry_pt: vm_address_t; + routine_number : int); + +/* + * Establish restart pc for interrupted atomic sequences. + * This reuses the message number for the old task_get_io_port. + * See task_info.h for description of flavors. + * + */ +routine task_ras_control( + target_task : task_t; + basepc : vm_address_t; + boundspc : vm_address_t; + flavor : int); + + + +skip; /* old host_ipc_statistics */ +skip; /* old port_names */ +skip; /* old port_type */ +skip; /* old port_rename */ +skip; /* old port_allocate */ +skip; /* old port_deallocate */ +skip; /* old port_set_backlog */ +skip; /* old port_status */ +skip; /* old port_set_allocate */ +skip; /* old port_set_deallocate */ +skip; /* old port_set_add */ +skip; /* old port_set_remove */ +skip; /* old port_set_status */ +skip; /* old port_insert_send */ +skip; /* old port_extract_send */ +skip; /* old port_insert_receive */ +skip; /* old port_extract_receive */ + +/* + * Map a user-defined memory object into the virtual address + * space of the target task. If desired (anywhere is TRUE), + * the kernel will find a suitable address range of the + * specified size; else, the specific address will be allocated. + * + * The beginning address of the range will be aligned on a virtual + * page boundary, be at or beyond the address specified, and + * meet the mask requirements (bits turned on in the mask must not + * be turned on in the result); the size of the range, in bytes, + * will be rounded up to an integral number of virtual pages. + * + * The memory in the resulting range will be associated with the + * specified memory object, with the beginning of the memory range + * referring to the specified offset into the memory object. + * + * The mapping will take the current and maximum protections and + * the inheritance attributes specified; see the vm_protect and + * vm_inherit calls for a description of these attributes. + * + * If desired (copy is TRUE), the memory range will be filled + * with a copy of the data from the memory object; this copy will + * be private to this mapping in this target task. Otherwise, + * the memory in this mapping will be shared with other mappings + * of the same memory object at the same offset (in this task or + * in other tasks). [The Mach kernel only enforces shared memory + * consistency among mappings on one host with similar page alignments. + * The user-defined memory manager for this object is responsible + * for further consistency.] + */ +#ifdef EMULATOR +routine htg_vm_map( + target_task : vm_task_t; + ureplyport reply_port : mach_port_make_send_once_t; + inout address : vm_address_t; + size : vm_size_t; + mask : vm_address_t; + anywhere : boolean_t; + memory_object : memory_object_t; + offset : vm_offset_t; + copy : boolean_t; + cur_protection : vm_prot_t; + max_protection : vm_prot_t; + inheritance : vm_inherit_t); +#else /* EMULATOR */ +routine vm_map( + target_task : vm_task_t; + inout address : vm_address_t; + size : vm_size_t; + mask : vm_address_t; + anywhere : boolean_t; + memory_object : memory_object_t; + offset : vm_offset_t; + copy : boolean_t; + cur_protection : vm_prot_t; + max_protection : vm_prot_t; + inheritance : vm_inherit_t); +#endif /* EMULATOR */ + +/* + * Indicate that a range of the specified memory object cannot + * be provided at this time. [Threads waiting for memory pages + * specified by this call will experience a memory exception. + * Only threads waiting at the time of the call are affected.] + */ +simpleroutine memory_object_data_error( + memory_control : memory_object_control_t; + offset : vm_offset_t; + size : vm_size_t; + error_value : kern_return_t); + +/* + * Make decisions regarding the use of the specified + * memory object. + */ +simpleroutine memory_object_set_attributes( + memory_control : memory_object_control_t; + object_ready : boolean_t; + may_cache : boolean_t; + copy_strategy : memory_object_copy_strategy_t); + +/* + */ +simpleroutine memory_object_destroy( + memory_control : memory_object_control_t; + reason : kern_return_t); + +/* + * Provide the data contents of a range of the given memory + * object, with the access restriction specified, optional + * precious attribute, and reply message. [Only + * whole virtual pages of data can be accepted; partial pages + * will be discarded. Data should be provided on request, but + * may be provided in advance as desired. When data already + * held by this kernel is provided again, the new data is ignored. + * The access restriction is the subset of {read, write, execute} + * which are prohibited. The kernel may not provide any data (or + * protection) consistency among pages with different virtual page + * alignments within the same object. The precious value controls + * how the kernel treats the data. If it is FALSE, the kernel treats + * its copy as a temporary and may throw it away if it hasn't been + * changed. If the precious value is TRUE, the kernel treats its + * copy as a data repository and promises to return it to the manager; + * the manager may tell the kernel to throw it away instead by flushing + * and not cleaning the data -- see memory_object_lock_request. The + * reply_to port is for a compeletion message; it will be + * memory_object_supply_completed.] + */ + +simpleroutine memory_object_data_supply( + memory_control : memory_object_control_t; + offset : vm_offset_t; + data : pointer_t, Dealloc[]; + lock_value : vm_prot_t; + precious : boolean_t; + reply_to : mach_port_t = + MACH_MSG_TYPE_MAKE_SEND_ONCE|polymorphic); + +simpleroutine memory_object_ready( + memory_control : memory_object_control_t; + may_cache : boolean_t; + copy_strategy : memory_object_copy_strategy_t); + +simpleroutine memory_object_change_attributes( + memory_control : memory_object_control_t; + may_cache : boolean_t; + copy_strategy : memory_object_copy_strategy_t; + reply_to : mach_port_t = + MACH_MSG_TYPE_MAKE_SEND_ONCE|polymorphic); + +skip; /* old host_callout_statistics_reset */ +skip; /* old port_set_select */ +skip; /* old port_set_backup */ + +/* + * Set/Get special properties of memory associated + * to some virtual address range, such as cachability, + * migrability, replicability. Machine-dependent. + */ +routine vm_machine_attribute( + target_task : vm_task_t; + address : vm_address_t; + size : vm_size_t; + attribute : vm_machine_attribute_t; + inout value : vm_machine_attribute_val_t); + +/*skip;*/ /* old host_fpa_counters_reset */ + +/* + * This routine is created for allocating DMA buffers. + * We are going to get a contiguous physical memory + * and its physical address in addition to the virtual address. + */ +routine vm_dma_buff_alloc( + host_priv : host_priv_t; + target_task : vm_task_t; + size : vm_size_t; + out vaddr : vm_address_t; + out paddr : vm_address_t); + +/* + * There is no more room in this interface for additional calls. + */ diff --git a/libddekit/malloc.c b/libddekit/malloc.c index c3735bdb..a30cd7b7 100644 --- a/libddekit/malloc.c +++ b/libddekit/malloc.c @@ -29,6 +29,9 @@ * * Each chunk stores its size in the first word for free() to work. */ + +#include + void *ddekit_simple_malloc(unsigned size) { return malloc (size); diff --git a/libddekit/memory.c b/libddekit/memory.c index 93853e55..27be4eeb 100644 --- a/libddekit/memory.c +++ b/libddekit/memory.c @@ -11,8 +11,10 @@ */ #include "ddekit/memory.h" +#include "ddekit/panic.h" extern void * linux_kmalloc (unsigned int size, int priority); +extern void linux_kfree (void *p); /**************** @@ -110,6 +112,7 @@ void *ddekit_slab_get_data(struct ddekit_slab * slab) #if 0 return l4slab_get_data(&slab->cache); #endif + return NULL; } @@ -154,7 +157,7 @@ struct ddekit_slab * ddekit_slab_init(unsigned size, int contiguous) */ void ddekit_large_free(void *objp) { - return linux_kfree (objp); + linux_kfree (objp); } diff --git a/libddekit/pci.c b/libddekit/pci.c index 32e02b84..5c3f4ef6 100644 --- a/libddekit/pci.c +++ b/libddekit/pci.c @@ -1,4 +1,8 @@ +#include #include + +#include "ddekit/assert.h" +#include "ddekit/printf.h" #include "ddekit/pci.h" #include "config.h" @@ -43,8 +47,8 @@ void ddekit_pci_init(void) dev_iter = pci_slot_match_iterator_create (NULL); while ((pci_dev = pci_device_next (dev_iter)) != NULL) { if (slots_found == MAX_PCI_DEVS) { - LOGd(dbg_this, "find more than %d pci devices", - slots_found); + ddekit_printf ("find more than %d pci devices", + slots_found); break; } /* Pretend all our devices are chained to exactly one bus. */ @@ -68,7 +72,7 @@ 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); + ddekit_printf ("searching for dev #%d", nr); if (nr >= 0 && nr < MAX_PCI_DEVS && !invalid_device(&ddekit_pci_bus[nr])) { dev = &ddekit_pci_bus[nr]; @@ -89,7 +93,8 @@ ddekit_pci_dev_t *ddekit_pci_find_device(int *bus, int *slot, int *func, Assert(slot); Assert(func); - LOGd(dbg_this, "start %p (slot %d)", start, start ? start->slot : -1); + ddekit_printf ("start %p (slot %d)", + start, start ? start->slot : -1); int idx = start ? start->slot + 1 : 0; for ( ; idx < MAX_PCI_DEVS; ++idx) { @@ -214,7 +219,8 @@ int ddekit_pci_writel(int bus, int slot, int func, int pos, ddekit_uint32_t val int ddekit_pci_enable_device(struct ddekit_pci_dev *dev) { - return pci_device_enable (dev->dev); + pci_device_enable (dev->dev); + return 0; } int ddekit_pci_disable_device(struct ddekit_pci_dev *dev) @@ -238,7 +244,7 @@ int ddekit_pci_disable_device(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_vendor(struct ddekit_pci_dev *dev) { - return dev->dev.vendor_id; + return dev->dev->vendor_id; } @@ -251,7 +257,7 @@ unsigned short ddekit_pci_get_vendor(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_device_id(struct ddekit_pci_dev *dev) { - return dev->dev.device_id; + return dev->dev->device_id; } @@ -264,7 +270,7 @@ unsigned short ddekit_pci_get_device_id(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_sub_vendor(struct ddekit_pci_dev *dev) { - return dev->dev.subvendor_id; + return dev->dev->subvendor_id; } @@ -277,7 +283,7 @@ unsigned short ddekit_pci_get_sub_vendor(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_sub_device(struct ddekit_pci_dev *dev) { - return dev->dev.subdevice_id; + return dev->dev->subdevice_id; } @@ -290,7 +296,7 @@ unsigned short ddekit_pci_get_sub_device(struct ddekit_pci_dev *dev) */ unsigned ddekit_pci_get_dev_class(struct ddekit_pci_dev *dev) { - return dev->dev.device_class; + return dev->dev->device_class; } @@ -303,7 +309,7 @@ unsigned ddekit_pci_get_dev_class(struct ddekit_pci_dev *dev) */ unsigned long ddekit_pci_get_irq(struct ddekit_pci_dev *dev) { - return dev->dev.irq; + return dev->dev->irq; } @@ -345,10 +351,11 @@ char *ddekit_pci_get_slot_name(struct ddekit_pci_dev *dev) */ ddekit_pci_res_t *ddekit_pci_get_resource(struct ddekit_pci_dev *dev, unsigned int idx) { - if (idx > L4IO_PCIDEV_RES) + // TODO +// if (idx > L4IO_PCIDEV_RES) return NULL; - //TODO return (ddekit_pci_res_t *)(&(dev->l4dev.res[idx])); +// return (ddekit_pci_res_t *)(&(dev->l4dev.res[idx])); } diff --git a/libddekit/printf.c b/libddekit/printf.c index bbd58863..72ff5003 100644 --- a/libddekit/printf.c +++ b/libddekit/printf.c @@ -4,7 +4,10 @@ * \date 2006-03-01 */ +#include +#include #include +#include #include #include "ddekit/printf.h" diff --git a/libddekit/thread.c b/libddekit/thread.c index a095db2f..081a4742 100644 --- a/libddekit/thread.c +++ b/libddekit/thread.c @@ -3,14 +3,18 @@ #include #include #include +#include +#include +#include +#include "ddekit/memory.h" #include "ddekit/semaphore.h" #include "list.h" #include "ddekit/thread.h" #define DDEKIT_THREAD_STACK_SIZE 0x2000 /* 8 KB */ -static struct ddekit_slab *ddekit_stack_slab = NULL; +//static struct ddekit_slab *ddekit_stack_slab = NULL; struct _ddekit_private_data { struct list list; @@ -18,8 +22,7 @@ struct _ddekit_private_data { /* point to the thread who has the private data. */ struct ddekit_thread *thread; mach_msg_header_t wakeupmsg; - -} +}; struct ddekit_thread { struct cthread thread; @@ -64,20 +67,20 @@ static error_t _create_wakeupmsg (struct _ddekit_private_data *data) return 0; } -static void setup_thread (cthread_t *t, const char *name) { +static void setup_thread (struct ddekit_thread *t, const char *name) { error_t err; struct _ddekit_private_data *private_data; if (name) { - const char *cpy = NULL; + char *cpy = NULL; - cpy = malloc (strlen (name) + 1); + cpy = ddekit_simple_malloc (strlen (name) + 1); if (cpy == NULL) error (0, 0, "fail to allocate memory"); else strcpy (cpy, name); - cthread_set_name (t, name); + cthread_set_name (&t->thread, name); } /* @@ -92,20 +95,21 @@ static void setup_thread (cthread_t *t, const char *name) { private_data->sleep_cond = condition_alloc (); condition_init (private_data->sleep_cond); - private_data->list = {&private_data->list, &private_data->list}; + private_data->list.prev = &private_data->list; + private_data->list.next = &private_data->list; private_data->thread = t; err = _create_wakeupmsg (private_data); - // TODO I need to change this. - assert_perror (err); + if (err) + error (1, err, "_create_wakeupmsg"); - cthread_set_ldata (t, private_data); + cthread_set_ldata (&t->thread, private_data); } ddekit_thread_t *ddekit_thread_setup_myself(const char *name) { ddekit_thread_t *td = ddekit_thread_myself(); - setup_thread (&td->thread, name); + setup_thread (td, name); return td; } @@ -116,7 +120,7 @@ ddekit_thread_t *ddekit_thread_create(void (*fun)(void *), void *arg, const char // before initialization is completed. td = (ddekit_thread_t *) cthread_fork (fun, arg); cthread_detach (&td->thread); - setup_thread (&td->thread, name); + setup_thread (td, name); return td; } @@ -180,7 +184,7 @@ void ddekit_thread_sleep(ddekit_lock_t *lock) { // TODO condition_wait cannot guarantee that the thread is // woke up by another thread, maybe by signals. // Does it matter here? - condition_wait (data->sleep_cond, lock); + condition_wait (data->sleep_cond, (struct mutex *) *lock); } void dekit_thread_wakeup(ddekit_thread_t *td) { @@ -205,7 +209,7 @@ void ddekit_thread_exit() { name = cthread_name (t); cthread_set_name (t, NULL); - free (name); + ddekit_simple_free ((char *) name); cthread_exit (0); } @@ -225,10 +229,18 @@ void ddekit_yield(void) } void ddekit_init_threads() { + char *str = "main"; + char *name = ddekit_simple_malloc (strlen (str) + 1); + + strcpy (name, str); // TODO maybe the name has already been set. - cthread_set_name (cthread_self (), "main"); + cthread_set_name (cthread_self (), name); } +/********************************************************************** + * semaphore + **********************************************************************/ + /* Block THREAD. */ static error_t _timedblock (struct _ddekit_private_data *data, const struct timespec *abstime) @@ -281,16 +293,16 @@ static void _block (struct _ddekit_private_data *data) assert_perror (err); } -static int _sem_timedwait_internal (sem_t *restrict sem, +static int _sem_timedwait_internal (ddekit_sem_t *restrict sem, const struct timespec *restrict timeout) { - struct ddekit_private_data *self_private_data; + struct _ddekit_private_data *self_private_data; spin_lock (&sem->lock); if (sem->value > 0) { /* Successful down. */ sem->value --; - spin_unlock (&sem->__lock); + spin_unlock (&sem->lock); return 0; } @@ -350,13 +362,14 @@ ddekit_sem_t *ddekit_sem_init(int value) { (ddekit_sem_t *) ddekit_simple_malloc (sizeof (*sem)); sem->lock = SPIN_LOCK_INITIALIZER; - sem->head = {&sem->head, &sem->head}; + 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_ENTRY (&sem->head)) { + if (!EMPTY_LIST (&sem->head)) { error (0, EBUSY, "ddekit_sem_deinit"); } else @@ -388,11 +401,11 @@ int ddekit_sem_down_timed(ddekit_sem_t *sem, int timo) { timeout.tv_sec = timo / 1000; timeout.tv_nsec = (timo % 1000) * 1000 * 1000; - return __sem_timedwait_internal (sem, &timeout); + return _sem_timedwait_internal (sem, &timeout); } void ddekit_sem_up(ddekit_sem_t *sem) { - struct _ddekit_thread_data *wakeup; + struct _ddekit_private_data *wakeup; spin_lock (&sem->lock); if (sem->value > 0) { @@ -400,26 +413,25 @@ void ddekit_sem_up(ddekit_sem_t *sem) { assert (EMPTY_LIST (&sem->head)); sem->value ++; spin_unlock (&sem->lock); - return 0; + return; } if (EMPTY_LIST (&sem->head)) { /* No one waiting. */ sem->value = 1; spin_unlock (&sem->lock); - return 0; + return; } /* Wake someone up. */ /* First dequeue someone. */ - wakeup = (struct _ddekit_private_data *) remove_entry_end (&sem->head); + wakeup = LIST_ENTRY (remove_entry_end (&sem->head), + struct _ddekit_private_data, list); /* Then drop the lock and transfer control. */ spin_unlock (&sem->lock); if (wakeup) _thread_wakeup (wakeup); - - return 0; } diff --git a/libddekit/timer.c b/libddekit/timer.c index d0a6ccc0..f8bfc7a1 100644 --- a/libddekit/timer.c +++ b/libddekit/timer.c @@ -2,6 +2,9 @@ #include #include +#include "ddekit/memory.h" +#include "ddekit/assert.h" +#include "ddekit/semaphore.h" #include "ddekit/timer.h" #define __DEBUG 0 @@ -118,7 +121,7 @@ int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout) * necessary to notify the timer thread. */ if (t == timer_list) { - Assert(!l4_is_nil_id(timer_thread)); + Assert(timer_thread); __notify_timer_thread(); } @@ -329,6 +332,6 @@ void ddekit_init_timers(void) root_jiffies = (long long) tp.tv_sec * HZ + ((long long) tp.tv_usec * HZ) / 1000000; - timer_thread = cthread_fork ((cthread_fn_t) timer_function, 0); + timer_thread = cthread_fork ((cthread_fn_t) ddekit_timer_thread, 0); cthread_detach (timer_thread); } 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 -- cgit v1.2.3 From 974a402ed6a28e7801f3c6202516ef232d73256a Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 6 Dec 2009 19:13:54 +0100 Subject: Redefine HZ. --- libddekit/include/ddekit/timer.h | 1 + libddekit/timer.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/include/ddekit/timer.h b/libddekit/include/ddekit/timer.h index a57c8fce..bb30e1f9 100644 --- a/libddekit/include/ddekit/timer.h +++ b/libddekit/include/ddekit/timer.h @@ -4,6 +4,7 @@ #include "ddekit/thread.h" #define jiffies fetch_jiffies() +#define HZ 100 enum { diff --git a/libddekit/timer.c b/libddekit/timer.c index f8bfc7a1..be23ee14 100644 --- a/libddekit/timer.c +++ b/libddekit/timer.c @@ -19,7 +19,6 @@ long long root_jiffies; * So, if someone schedules a timeout to expire in 2 seconds, * this expires date will be in jiffies + 2 * HZ. */ -extern unsigned long HZ; typedef struct _timer { -- cgit v1.2.3 From c27b7fd8a10207d5c1802370b2bb8c2dbcd7f153 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 6 Dec 2009 23:33:03 +0100 Subject: fix a bug in printf.c. --- libddekit/printf.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'libddekit') diff --git a/libddekit/printf.c b/libddekit/printf.c index 72ff5003..1996987f 100644 --- a/libddekit/printf.c +++ b/libddekit/printf.c @@ -71,10 +71,16 @@ int ddekit_vprintf(const char *fmt, va_list va) int log_init () { - char *log_file_name = mktemp ("/tmp/dde_log.XXXXXX"); - output = fopen (log_file_name, "a+"); + 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", log_file_name); + error (0, errno, "open %s", template); return -1; } return 0; -- cgit v1.2.3 From 03ce78689d4b67a4380938203b07cd140a25614b Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 6 Dec 2009 23:34:15 +0100 Subject: kmem gets its own priv host port by itself. --- libddekit/kmem.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/kmem.c b/libddekit/kmem.c index 2e6f7340..9814b501 100644 --- a/libddekit/kmem.c +++ b/libddekit/kmem.c @@ -22,6 +22,7 @@ * */ +#include #include #include #include "mach_U.h" @@ -120,8 +121,13 @@ int phys_to_virt (vm_address_t addr) void linux_kmem_init () { - extern mach_port_t priv_host; + mach_port_t priv_host; int i, j; + error_t err; + + err = get_privileged_ports (&priv_host, NULL); + if (err) + error (2, err, "get_privileged_ports"); for (i = 0; i < MEM_CHUNKS; i++) { -- cgit v1.2.3 From d0dac02619cdfd47cc6e1f2a29a48b9a8eeaf34f Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 6 Dec 2009 23:45:33 +0100 Subject: fix Makefile to compile the library. --- libddekit/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index 67a3b193..018d67c9 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -37,11 +37,11 @@ installhdrs = MIGSTUBS = deviceUser.o machUser.o OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS)) -HURDLIBS = threads ports +HURDLIBS = threads ports shouldbeinlibc MIGCOMSFLAGS = -prefix dde_ include ../Makeconf LDFLAGS += -lpciaccess -CFLAGS += -Iinclude -Iinclude/ddekit +CFLAGS += -Iinclude -- cgit v1.2.3 From aba36be0e07f39429b6ac19024b8c6e457cc26b0 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Mon, 7 Dec 2009 01:32:01 +0100 Subject: support allocation of large chunks of memory. --- libddekit/kmem.c | 81 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 23 deletions(-) (limited to 'libddekit') diff --git a/libddekit/kmem.c b/libddekit/kmem.c index 9814b501..49b9a9d3 100644 --- a/libddekit/kmem.c +++ b/libddekit/kmem.c @@ -22,6 +22,7 @@ * */ +#include #include #include #include @@ -42,6 +43,10 @@ extern int printf (const char *, ...); Increase MEM_CHUNKS if the kernel is running out of memory. */ #define MEM_CHUNK_SIZE (64 * 1024) #define MEM_CHUNKS 7 +#define MEM_CHUNKS_TOTAL (MEM_CHUNKS + 5) + +/* round up the size at alignment of page size. */ +#define ROUND_UP(size) ((size) + __vm_page_size - 1) & (~(__vm_page_size - 1)) /* Mininum amount that linux_kmalloc will allocate. */ #define MIN_ALLOC 12 @@ -78,12 +83,16 @@ void free_pages (unsigned long addr, unsigned long order); static struct mutex mem_lock = MUTEX_INITIALIZER; -/* Chunks from which pages are allocated. */ -static struct chunkhdr pages_free[MEM_CHUNKS]; +/* Chunks from which pages are allocated. + * The extra slots are used to hold the huge chunks (> MEM_CHUNKS_SIZE) + * which are allocated by the user. */ +static struct chunkhdr pages_free[MEM_CHUNKS_TOTAL]; /* Memory list maintained by linux_kmalloc. */ static struct pagehdr *memlist; +static mach_port_t priv_host; + /* Some statistics. */ int num_block_coalesce = 0; int num_page_collect = 0; @@ -93,13 +102,13 @@ int virt_to_phys (vm_address_t addr) { int i; - for (i = 0; i < MEM_CHUNKS; i++) + for (i = 0; i < MEM_CHUNKS_TOTAL; i++) { if (pages_free[i].start <= addr && pages_free[i].end > addr) return addr - pages_free[i].start + pages_free[i].pstart; } debug ("an address not in any chunks."); - abort (); + return -1; } int phys_to_virt (vm_address_t addr) @@ -107,21 +116,20 @@ int phys_to_virt (vm_address_t addr) #define CHUNK_SIZE(chunk) ((chunk)->end - (chunk)->start) int i; - for (i = 0; i < MEM_CHUNKS; i++) + for (i = 0; i < MEM_CHUNKS_TOTAL; i++) { if (pages_free[i].pstart <= addr && pages_free[i].pstart + CHUNK_SIZE (pages_free + i) > addr) return addr - pages_free[i].pstart + pages_free[i].start; } debug ("an address not in any chunks."); - abort (); + return -1; } /* Initialize the Linux memory allocator. */ void linux_kmem_init () { - mach_port_t priv_host; int i, j; error_t err; @@ -141,20 +149,9 @@ linux_kmem_init () abort (); assert (pages_free[i].start); -// assert ((pages_free[i].start & 0xffff) == 0); - -// /* Sanity check: ensure pages are contiguous and within DMA limits. */ -// for (p = pages, j = 0; j < MEM_CHUNK_SIZE - PAGE_SIZE; j += PAGE_SIZE) -// { -// assert (p->phys_addr < 16 * 1024 * 1024); -// assert (p->phys_addr + PAGE_SIZE -// == ((vm_page_t) p->pageq.next)->phys_addr); -// -// p = (vm_page_t) p->pageq.next; -// } pages_free[i].end = pages_free[i].start + MEM_CHUNK_SIZE; - assert (pages_free[i].end <= 16 * 1024 * 1024); + assert (pages_free[i].pstart + MEM_CHUNK_SIZE <= 16 * 1024 * 1024); /* Initialize free page bitmap. */ pages_free[i].bitmap = 0; @@ -163,6 +160,10 @@ linux_kmem_init () pages_free[i].bitmap |= 1 << j; } + /* Initialize the space for extra slots. */ + memset (pages_free + i, 0, + sizeof (pages_free[0]) * (MEM_CHUNKS_TOTAL - MEM_CHUNKS)); + linux_mem_avail = (MEM_CHUNKS * MEM_CHUNK_SIZE) >> PAGE_SHIFT; } @@ -263,12 +264,32 @@ linux_kmalloc (unsigned int size, int priority) else size = (size + sizeof (int) - 1) & ~(sizeof (int) - 1); - assert (size <= (MEM_CHUNK_SIZE - - sizeof (struct pagehdr) - - sizeof (struct blkhdr))); - mutex_lock (&mem_lock); + if (size > (MEM_CHUNK_SIZE - sizeof (struct pagehdr) + - sizeof (struct blkhdr))) + { + error_t err; + int i; + + /* Find an extra slot. */ + for (i = MEM_CHUNKS; i < MEM_CHUNKS_TOTAL; i++) + if (pages_free[i].end == 0) + break; + + assert (i < MEM_CHUNKS_TOTAL); + size = ROUND_UP (size); + err = vm_dma_buff_alloc (priv_host, mach_task_self (), size, + &pages_free[i].start, &pages_free[i].pstart); + if (!err) + pages_free[i].end = pages_free[i].start + size; + mutex_unlock (&mem_lock); + printf ("allocate %d bytes at (virt: %x, phys: %x), slot %d\n", + size, pages_free[i].start, pages_free[i].pstart, i); + + return err ? NULL : (void *) pages_free[i].start; + } + again: check_page_list (__LINE__); @@ -347,10 +368,24 @@ linux_kfree (void *p) { struct blkhdr *bh; struct pagehdr *ph; + int i; assert (((int) p & (sizeof (int) - 1)) == 0); mutex_lock (&mem_lock); + + for (i = MEM_CHUNKS; i < MEM_CHUNKS_TOTAL; i++) + { + if ((vm_address_t) p == pages_free[i].start) + { + // TODO I think the page cannot be deallocated. + vm_deallocate (mach_task_self (), (vm_address_t) p, + pages_free[i].end - pages_free[i].start); + memset (pages_free + i, 0, sizeof (pages_free[i])); + mutex_unlock (&mem_lock); + return; + } + } check_page_list (__LINE__); -- cgit v1.2.3 From badbd862e4ab01010be9cd0b82bdc7734f061deb Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Mon, 7 Dec 2009 01:59:14 +0100 Subject: fix a bug in printf.c --- libddekit/printf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libddekit') diff --git a/libddekit/printf.c b/libddekit/printf.c index 1996987f..0d4ec52f 100644 --- a/libddekit/printf.c +++ b/libddekit/printf.c @@ -29,7 +29,7 @@ int ddekit_print(const char *msg) return -1; ret = fprintf (output, "%s", msg); - if (!ret) + if (ret > 0) fflush (output); return ret; } @@ -62,7 +62,7 @@ int ddekit_vprintf(const char *fmt, va_list va) int ret; ret = vasprintf (&tmp, fmt, va); - if (!ret) { + if (ret > 0) { ret = ddekit_print (tmp); free (tmp); } -- cgit v1.2.3 From d12886c5281918f46b02f8cf3617858b11c44812 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Mon, 7 Dec 2009 02:00:09 +0100 Subject: Use linux_kmalloc only when we need contiguous physical memory. --- libddekit/memory.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'libddekit') diff --git a/libddekit/memory.c b/libddekit/memory.c index 27be4eeb..1ffb15b0 100644 --- a/libddekit/memory.c +++ b/libddekit/memory.c @@ -80,7 +80,10 @@ struct ddekit_slab */ void *ddekit_slab_alloc(struct ddekit_slab * slab) { - return linux_kmalloc (slab->size, 0); + if (slab->contiguous) + return linux_kmalloc (slab->size, 0); + else + return ddekit_simple_malloc (slab->size); } @@ -89,7 +92,10 @@ void *ddekit_slab_alloc(struct ddekit_slab * slab) */ void ddekit_slab_free(struct ddekit_slab * slab, void *objp) { - linux_kfree (objp); + if (slab->contiguous) + linux_kfree (objp); + else + ddekit_simple_free (objp); } @@ -168,7 +174,6 @@ void ddekit_large_free(void *objp) */ void *ddekit_large_malloc(int size) { - // TODO I hope linux_kmalloc can provide large enough pages. return linux_kmalloc (size, 0); } -- cgit v1.2.3 From 9341952a7cea0d39b871ecdb6ac153fc820524c8 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Mon, 7 Dec 2009 02:25:32 +0100 Subject: Make ddekit_simple_malloc/free inline. --- libddekit/Makefile | 2 +- libddekit/include/ddekit/memory.h | 13 +++++++++-- libddekit/malloc.c | 49 --------------------------------------- libddekit/memory.c | 3 +++ 4 files changed, 15 insertions(+), 52 deletions(-) delete mode 100644 libddekit/malloc.c (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index 018d67c9..f2e52f25 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -19,7 +19,7 @@ dir := libddekit makemode := library libname = libddekit -SRCS= condvar.c init.c interrupt.c lock.c malloc.c memory.c \ +SRCS= condvar.c init.c interrupt.c lock.c memory.c \ pci.c pgtab.c printf.c resources.c list.c \ thread.c timer.c kmem.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ diff --git a/libddekit/include/ddekit/memory.h b/libddekit/include/ddekit/memory.h index 051a4d9e..2c573d8f 100644 --- a/libddekit/include/ddekit/memory.h +++ b/libddekit/include/ddekit/memory.h @@ -123,6 +123,9 @@ void *ddekit_contig_malloc( ** Simple memory allocator ** *****************************/ +#include +#include "ddekit/inline.h" + /** * Allocate memory block via simple allocator * @@ -132,13 +135,19 @@ void *ddekit_contig_malloc( * 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); +static INLINE 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); +static INLINE void ddekit_simple_free(void *p) +{ + free (p); +} #endif diff --git a/libddekit/malloc.c b/libddekit/malloc.c deleted file mode 100644 index a30cd7b7..00000000 --- a/libddekit/malloc.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - 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 - -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 index 1ffb15b0..781a4bae 100644 --- a/libddekit/memory.c +++ b/libddekit/memory.c @@ -160,6 +160,9 @@ struct ddekit_slab * ddekit_slab_init(unsigned size, int contiguous) * 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) { -- cgit v1.2.3 From 92b35532d8707fb6aab8d450327fc8b6b64b0118 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 11 Dec 2009 13:51:22 +0100 Subject: allow to print information to stdout. --- libddekit/printf.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'libddekit') diff --git a/libddekit/printf.c b/libddekit/printf.c index 0d4ec52f..a35c4bc9 100644 --- a/libddekit/printf.c +++ b/libddekit/printf.c @@ -9,9 +9,11 @@ #include #include #include +#include #include "ddekit/printf.h" +extern boolean_t using_std; static FILE *output; /** @@ -71,17 +73,23 @@ int ddekit_vprintf(const char *fmt, va_list va) int log_init () { - char template[] = "/var/log/dde_log.XXXXXX"; - int ret = mkstemp (template); - if (ret < 0) { - error (0, errno, "mkstemp"); - return -1; + if (using_std) { + output = stdout; } + 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; + output = fopen (template, "a+"); + if (!output) { + error (0, errno, "open %s", template); + return -1; + } } + return 0; } -- cgit v1.2.3 From 3d4eb7565f63ec437a6c74f42cfa092cfb192f16 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 11 Dec 2009 13:52:23 +0100 Subject: Use ddekit lock instead of mutex. --- libddekit/include/ddekit/timer.h | 2 +- libddekit/timer.c | 38 ++++++++++++++++++++++++-------------- 2 files changed, 25 insertions(+), 15 deletions(-) (limited to 'libddekit') diff --git a/libddekit/include/ddekit/timer.h b/libddekit/include/ddekit/timer.h index bb30e1f9..c0bea6bf 100644 --- a/libddekit/include/ddekit/timer.h +++ b/libddekit/include/ddekit/timer.h @@ -3,7 +3,7 @@ #include "ddekit/thread.h" -#define jiffies fetch_jiffies() +#define jiffies (fetch_jiffies()) #define HZ 100 enum diff --git a/libddekit/timer.c b/libddekit/timer.c index be23ee14..4944be69 100644 --- a/libddekit/timer.c +++ b/libddekit/timer.c @@ -2,6 +2,7 @@ #include #include +#include "ddekit/lock.h" #include "ddekit/memory.h" #include "ddekit/assert.h" #include "ddekit/semaphore.h" @@ -31,7 +32,7 @@ typedef struct _timer static ddekit_timer_t *timer_list = NULL; ///< list of pending timers -static struct mutex timer_lock = MUTEX_INITIALIZER; ///< lock to access timer_list +static ddekit_lock_t timer_lock; ///< lock to access timer_list static cthread_t timer_thread; ///< 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 @@ -53,11 +54,13 @@ static void dump_list(char *msg) #endif } -int fetch_jiffies () +long 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; @@ -86,6 +89,7 @@ int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout) ddekit_timer_t *t = ddekit_simple_malloc(sizeof(ddekit_timer_t)); Assert(t); + printf ("add a timer at %ld\n", timeout); /* fill in values */ t->fn = fn; @@ -93,7 +97,7 @@ int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout) t->expires = timeout; t->next = NULL; - mutex_lock (&timer_lock); + ddekit_lock_lock (&timer_lock); t->id = timer_id_ctr++; @@ -124,7 +128,7 @@ int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout) __notify_timer_thread(); } - mutex_unlock (&timer_lock); + ddekit_lock_unlock (&timer_lock); dump_list("after add"); @@ -137,7 +141,7 @@ int ddekit_del_timer(int timer) ddekit_timer_t *it, *it_next; int ret = -1; - mutex_lock (&timer_lock); + ddekit_lock_lock (&timer_lock); /* no timer? */ if (!timer_list) { @@ -178,7 +182,7 @@ int ddekit_del_timer(int timer) } out: - mutex_unlock (&timer_lock); + ddekit_lock_unlock (&timer_lock); dump_list("after del"); @@ -197,7 +201,7 @@ int ddekit_timer_pending(int timer) ddekit_timer_t *t = NULL; int r = 0; - mutex_lock (&timer_lock); + ddekit_lock_lock (&timer_lock); t = timer_list; while (t) { @@ -208,7 +212,7 @@ int ddekit_timer_pending(int timer) t = t->next; } - mutex_unlock (&timer_lock); + ddekit_lock_unlock (&timer_lock); return r; } @@ -224,7 +228,7 @@ static ddekit_timer_t *get_next_timer(void) ddekit_timer_t *t = NULL; /* This function must be called with the timer_lock held. */ - Assert(timer_lock.holder == timer_thread); + Assert(ddekit_lock_owner (&timer_lock) == (int) timer_thread); if (timer_list && (timer_list->expires <= jiffies)) { @@ -251,7 +255,7 @@ static inline int __timer_sleep(unsigned to) { int err = 0; - mutex_unlock (&timer_lock); + ddekit_lock_unlock (&timer_lock); if (to == DDEKIT_TIMEOUT_NEVER) { ddekit_sem_down(notify_semaphore); @@ -266,7 +270,7 @@ static inline int __timer_sleep(unsigned to) #endif } - mutex_lock (&timer_lock); + ddekit_lock_lock (&timer_lock); return (err ? 1 : 0); } @@ -283,7 +287,7 @@ static void ddekit_timer_thread(void *arg) // l4thread_started(0); - mutex_lock (&timer_lock); + ddekit_lock_lock (&timer_lock); while (1) { ddekit_timer_t *timer = NULL; unsigned long to = DDEKIT_TIMEOUT_NEVER; @@ -301,11 +305,11 @@ static void ddekit_timer_thread(void *arg) __timer_sleep(to); while ((timer = get_next_timer()) != NULL) { - mutex_unlock (&timer_lock); + ddekit_lock_unlock (&timer_lock); //ddekit_printf("doing timer fn @ %p\n", timer->fn); timer->fn(timer->args); ddekit_simple_free(timer); - mutex_lock (&timer_lock); + ddekit_lock_lock (&timer_lock); } } // TODO how is the thread terminated? @@ -321,7 +325,12 @@ void ddekit_init_timers(void) { error_t err; struct timeval tp; + static boolean_t initialized = FALSE; + if (initialized) + return; + + initialized = TRUE; err = maptime_map (0, 0, &mapped_time); if (err) error (2, err, "cannot map time device"); @@ -331,6 +340,7 @@ void ddekit_init_timers(void) root_jiffies = (long long) tp.tv_sec * HZ + ((long long) tp.tv_usec * HZ) / 1000000; + ddekit_lock_init (&timer_lock); timer_thread = cthread_fork ((cthread_fn_t) ddekit_timer_thread, 0); cthread_detach (timer_thread); } -- cgit v1.2.3 From 0451c065a044b9791b5cfa6a2432bcb8d1342710 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 11 Dec 2009 15:14:14 +0100 Subject: destroy the port before the thread exits. --- libddekit/thread.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'libddekit') diff --git a/libddekit/thread.c b/libddekit/thread.c index 081a4742..48720584 100644 --- a/libddekit/thread.c +++ b/libddekit/thread.c @@ -187,8 +187,8 @@ void ddekit_thread_sleep(ddekit_lock_t *lock) { condition_wait (data->sleep_cond, (struct mutex *) *lock); } -void dekit_thread_wakeup(ddekit_thread_t *td) { - struct _ddekit_private_data *data = cthread_ldata (cthread_self ()); +void ddekit_thread_wakeup(ddekit_thread_t *td) { + struct _ddekit_private_data *data = cthread_ldata (&td->thread); condition_signal (data->sleep_cond); } @@ -198,12 +198,14 @@ void ddekit_thread_exit() { struct _ddekit_private_data *data; cthread_t t = cthread_self (); - // TODO I hope I don't need a lock to protect ldata and name. + // TODO I need a lock to protect ldata and name. /* I have to free the sleep condition variable * before the thread exits. */ data = cthread_ldata (t); cthread_set_ldata (t, NULL); + mach_port_destroy (mach_task_self (), + data->wakeupmsg.msgh_remote_port); condition_free (data->sleep_cond); ddekit_simple_free (data); -- cgit v1.2.3 From 17e978089ff52a13e633dc20f7ee0ba021f46d61 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 11 Dec 2009 15:18:19 +0100 Subject: Don't set the main thread name. --- libddekit/thread.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'libddekit') diff --git a/libddekit/thread.c b/libddekit/thread.c index 48720584..c1a9c6d5 100644 --- a/libddekit/thread.c +++ b/libddekit/thread.c @@ -231,12 +231,6 @@ void ddekit_yield(void) } void ddekit_init_threads() { - char *str = "main"; - char *name = ddekit_simple_malloc (strlen (str) + 1); - - strcpy (name, str); - // TODO maybe the name has already been set. - cthread_set_name (cthread_self (), name); } /********************************************************************** -- cgit v1.2.3 From f78cc8600bb68fe1970e1bbfbd4ffc8fffb866e2 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 13 Dec 2009 11:39:29 +0100 Subject: A new thread has been initialized when it starts. --- libddekit/thread.c | 83 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 22 deletions(-) (limited to 'libddekit') diff --git a/libddekit/thread.c b/libddekit/thread.c index c1a9c6d5..f9aa6e58 100644 --- a/libddekit/thread.c +++ b/libddekit/thread.c @@ -36,6 +36,28 @@ struct ddekit_sem int value; }; +static void _thread_cleanup () +{ + const char *name; + struct _ddekit_private_data *data; + cthread_t t = cthread_self (); + + // TODO I need a lock to protect ldata and name. + + /* I have to free the sleep condition variable + * before the thread exits. */ + data = cthread_ldata (t); + cthread_set_ldata (t, NULL); + mach_port_destroy (mach_task_self (), + data->wakeupmsg.msgh_remote_port); + condition_free (data->sleep_cond); + ddekit_simple_free (data); + + name = cthread_name (t); + cthread_set_name (t, NULL); + ddekit_simple_free ((char *) name); +} + /* Prepare a wakeup message. */ static error_t _create_wakeupmsg (struct _ddekit_private_data *data) { @@ -113,14 +135,49 @@ ddekit_thread_t *ddekit_thread_setup_myself(const char *name) { return td; } +typedef struct +{ + void (*fun)(void *); + void *arg; + struct condition cond; + struct mutex lock; + int status; +} priv_arg_t; + +static void* _priv_fun (void *arg) +{ + priv_arg_t *priv_arg = arg; + /* We wait until the initialization of the thread is finished. */ + mutex_lock (&priv_arg->lock); + while (!priv_arg->status) + condition_wait (&priv_arg->cond, &priv_arg->lock); + mutex_unlock (&priv_arg->lock); + + priv_arg->fun(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; + priv_arg_t *priv_arg = (priv_arg_t *) malloc (sizeof (*priv_arg)); + + priv_arg->fun = fun; + priv_arg->arg = arg; + condition_init (&priv_arg->cond); + mutex_init (&priv_arg->lock); + priv_arg->status = 0; - // TODO I should let the thread suspend - // before initialization is completed. - td = (ddekit_thread_t *) cthread_fork (fun, arg); + td = (ddekit_thread_t *) cthread_fork (_priv_fun, priv_arg); cthread_detach (&td->thread); setup_thread (td, name); + + /* Tell the new thread that initialization has been finished. */ + mutex_lock (&priv_arg->lock); + priv_arg->status = 1; + cond_signal (&priv_arg->cond); + mutex_unlock (&priv_arg->lock); + return td; } @@ -194,25 +251,7 @@ void ddekit_thread_wakeup(ddekit_thread_t *td) { } void ddekit_thread_exit() { - const char *name; - struct _ddekit_private_data *data; - cthread_t t = cthread_self (); - - // TODO I need a lock to protect ldata and name. - - /* I have to free the sleep condition variable - * before the thread exits. */ - data = cthread_ldata (t); - cthread_set_ldata (t, NULL); - mach_port_destroy (mach_task_self (), - data->wakeupmsg.msgh_remote_port); - condition_free (data->sleep_cond); - ddekit_simple_free (data); - - name = cthread_name (t); - cthread_set_name (t, NULL); - ddekit_simple_free ((char *) name); - + _thread_cleanup (); cthread_exit (0); } -- cgit v1.2.3 From c02fb40c744dc0789a69432d4d0b59f65cceac34 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 13 Dec 2009 12:24:02 +0100 Subject: Use a global lock to protect a thread's local data. --- libddekit/thread.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'libddekit') diff --git a/libddekit/thread.c b/libddekit/thread.c index f9aa6e58..b6ef987a 100644 --- a/libddekit/thread.c +++ b/libddekit/thread.c @@ -36,18 +36,20 @@ struct ddekit_sem int value; }; +static struct mutex global_lock = MUTEX_INITIALIZER; + static void _thread_cleanup () { const char *name; struct _ddekit_private_data *data; cthread_t t = cthread_self (); - // TODO I need a lock to protect ldata and name. - /* I have to free the sleep condition variable * before the thread exits. */ + mutex_lock (&global_lock); data = cthread_ldata (t); cthread_set_ldata (t, NULL); + mutex_unlock (&global_lock); mach_port_destroy (mach_task_self (), data->wakeupmsg.msgh_remote_port); condition_free (data->sleep_cond); @@ -125,7 +127,9 @@ static void setup_thread (struct ddekit_thread *t, const char *name) { if (err) error (1, err, "_create_wakeupmsg"); + mutex_lock (&global_lock); cthread_set_ldata (&t->thread, private_data); + mutex_unlock (&global_lock); } ddekit_thread_t *ddekit_thread_setup_myself(const char *name) { @@ -236,7 +240,11 @@ void ddekit_thread_nsleep(unsigned long nsecs) { } void ddekit_thread_sleep(ddekit_lock_t *lock) { - struct _ddekit_private_data *data = cthread_ldata (cthread_self ()); + struct _ddekit_private_data *data; + + mutex_lock (&global_lock); + data= cthread_ldata (cthread_self ()); + mutex_unlock (&global_lock); // TODO condition_wait cannot guarantee that the thread is // woke up by another thread, maybe by signals. @@ -245,8 +253,14 @@ void ddekit_thread_sleep(ddekit_lock_t *lock) { } void ddekit_thread_wakeup(ddekit_thread_t *td) { - struct _ddekit_private_data *data = cthread_ldata (&td->thread); + struct _ddekit_private_data *data; + + mutex_lock (&global_lock); + data = cthread_ldata (&td->thread); + mutex_unlock (&global_lock); + if (data == NULL) + return; condition_signal (data->sleep_cond); } @@ -348,7 +362,9 @@ static int _sem_timedwait_internal (ddekit_sem_t *restrict sem, } /* Add ourselves to the queue. */ + mutex_lock (&global_lock); self_private_data = cthread_ldata (cthread_self ()); + mutex_unlock (&global_lock); add_entry_head (&sem->head, (struct list *) self_private_data); spin_unlock (&sem->lock); -- cgit v1.2.3 From 5887e27b584ef586ebaa14a08ef4c5254ce373e3 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 13 Dec 2009 12:25:35 +0100 Subject: Setup the main thread when initializing ddekit. --- libddekit/thread.c | 1 + 1 file changed, 1 insertion(+) (limited to 'libddekit') diff --git a/libddekit/thread.c b/libddekit/thread.c index b6ef987a..cc2b0d53 100644 --- a/libddekit/thread.c +++ b/libddekit/thread.c @@ -284,6 +284,7 @@ void ddekit_yield(void) } void ddekit_init_threads() { + ddekit_thread_setup_myself ("main"); } /********************************************************************** -- cgit v1.2.3 From d14ef0ec0bf54f4a3290d5df196304f2b01b5901 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 15 Dec 2009 05:52:37 +0100 Subject: fix a bug (setting a thread name). --- libddekit/thread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/thread.c b/libddekit/thread.c index cc2b0d53..84fbb1d6 100644 --- a/libddekit/thread.c +++ b/libddekit/thread.c @@ -104,7 +104,7 @@ static void setup_thread (struct ddekit_thread *t, const char *name) { else strcpy (cpy, name); - cthread_set_name (&t->thread, name); + cthread_set_name (&t->thread, cpy); } /* -- cgit v1.2.3 From 8bf044ed70a43e5dcbd14f531e74221c4e939442 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 15 Dec 2009 06:16:50 +0100 Subject: fix a bug in condvar. --- libddekit/condvar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/condvar.c b/libddekit/condvar.c index bbd49417..391a20fa 100644 --- a/libddekit/condvar.c +++ b/libddekit/condvar.c @@ -24,7 +24,7 @@ ddekit_condvar_t *ddekit_condvar_init() { 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. */ - condition_wait (&cvp->cond, (struct mutex *) mp); + condition_wait (&cvp->cond, (struct mutex *) *mp); } int ddekit_condvar_wait_timed(ddekit_condvar_t *cvp, -- cgit v1.2.3 From 056abee2aedbcdf8f072ebaecb9487d6cdaa4f21 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 15 Dec 2009 06:34:27 +0100 Subject: Use ddekit condvar instead of the one in cthreads. --- libddekit/thread.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'libddekit') diff --git a/libddekit/thread.c b/libddekit/thread.c index 84fbb1d6..34a293e1 100644 --- a/libddekit/thread.c +++ b/libddekit/thread.c @@ -9,6 +9,7 @@ #include "ddekit/memory.h" #include "ddekit/semaphore.h" +#include "ddekit/condvar.h" #include "list.h" #include "ddekit/thread.h" @@ -18,7 +19,7 @@ struct _ddekit_private_data { struct list list; - condition_t sleep_cond; + ddekit_condvar_t *sleep_cond; /* point to the thread who has the private data. */ struct ddekit_thread *thread; mach_msg_header_t wakeupmsg; @@ -52,7 +53,7 @@ static void _thread_cleanup () mutex_unlock (&global_lock); mach_port_destroy (mach_task_self (), data->wakeupmsg.msgh_remote_port); - condition_free (data->sleep_cond); + ddekit_condvar_deinit (data->sleep_cond); ddekit_simple_free (data); name = cthread_name (t); @@ -116,9 +117,7 @@ static void setup_thread (struct ddekit_thread *t, const char *name) { private_data = (struct _ddekit_private_data *) ddekit_simple_malloc (sizeof (*private_data)); - private_data->sleep_cond = condition_alloc (); - condition_init (private_data->sleep_cond); - + 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; @@ -249,7 +248,7 @@ void ddekit_thread_sleep(ddekit_lock_t *lock) { // TODO condition_wait cannot guarantee that the thread is // woke up by another thread, maybe by signals. // Does it matter here? - condition_wait (data->sleep_cond, (struct mutex *) *lock); + ddekit_condvar_wait (data->sleep_cond, lock); } void ddekit_thread_wakeup(ddekit_thread_t *td) { @@ -261,7 +260,7 @@ void ddekit_thread_wakeup(ddekit_thread_t *td) { if (data == NULL) return; - condition_signal (data->sleep_cond); + ddekit_condvar_signal (data->sleep_cond); } void ddekit_thread_exit() { -- cgit v1.2.3 From 1f30702285010c0921c4d8266096c49e6f3bd533 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 15 Dec 2009 06:35:25 +0100 Subject: Add ddekit_condvar_deinit. --- libddekit/condvar.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'libddekit') diff --git a/libddekit/condvar.c b/libddekit/condvar.c index 391a20fa..55c57f8b 100644 --- a/libddekit/condvar.c +++ b/libddekit/condvar.c @@ -21,6 +21,10 @@ ddekit_condvar_t *ddekit_condvar_init() { return (ddekit_condvar_t *) cvp; } +void ddekit_condvar_deinit(ddekit_condvar_t *cvp) { + condition_free (&cvp->cond); +} + 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. */ -- cgit v1.2.3 From 0ea79b053d4a853d7bdd3363ccb6c132b2f7ee5c Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 29 Dec 2009 20:48:00 +0100 Subject: Don't include C library headers files in our header files. --- libddekit/Makefile | 2 +- libddekit/c_headers.h | 7 ++++++ libddekit/include/ddekit/memory.h | 13 ++--------- libddekit/include/ddekit/panic.h | 2 +- libddekit/include/ddekit/printf.h | 2 +- libddekit/malloc.c | 49 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 libddekit/c_headers.h create mode 100644 libddekit/malloc.c (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index f2e52f25..018d67c9 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -19,7 +19,7 @@ dir := libddekit makemode := library libname = libddekit -SRCS= condvar.c init.c interrupt.c lock.c memory.c \ +SRCS= condvar.c init.c interrupt.c lock.c malloc.c memory.c \ pci.c pgtab.c printf.c resources.c list.c \ thread.c timer.c kmem.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ diff --git a/libddekit/c_headers.h b/libddekit/c_headers.h new file mode 100644 index 00000000..6141e900 --- /dev/null +++ b/libddekit/c_headers.h @@ -0,0 +1,7 @@ +#ifndef __C_HEADERS_H__ +#define __C_HEADERS_H__ + +#include +#include + +#endif diff --git a/libddekit/include/ddekit/memory.h b/libddekit/include/ddekit/memory.h index 2c573d8f..051a4d9e 100644 --- a/libddekit/include/ddekit/memory.h +++ b/libddekit/include/ddekit/memory.h @@ -123,9 +123,6 @@ void *ddekit_contig_malloc( ** Simple memory allocator ** *****************************/ -#include -#include "ddekit/inline.h" - /** * Allocate memory block via simple allocator * @@ -135,19 +132,13 @@ void *ddekit_contig_malloc( * The blocks allocated via this allocator CANNOT be used for DMA or other * device operations, i.e., there exists no virt->phys mapping. */ -static INLINE void *ddekit_simple_malloc(unsigned size) -{ - return malloc (size); -} +void *ddekit_simple_malloc(unsigned size); /** * Free memory block via simple allocator * * \param p pointer to memory block */ -static INLINE void ddekit_simple_free(void *p) -{ - free (p); -} +void ddekit_simple_free(void *p); #endif diff --git a/libddekit/include/ddekit/panic.h b/libddekit/include/ddekit/panic.h index 11c46ebb..f036ab3e 100644 --- a/libddekit/include/ddekit/panic.h +++ b/libddekit/include/ddekit/panic.h @@ -3,7 +3,7 @@ /** \defgroup DDEKit_util */ -#include +#include "c_headers.h" /** Panic - print error message and enter the kernel debugger. * \ingroup DDEKit_util diff --git a/libddekit/include/ddekit/printf.h b/libddekit/include/ddekit/printf.h index 35b0dfa1..aa086c71 100644 --- a/libddekit/include/ddekit/printf.h +++ b/libddekit/include/ddekit/printf.h @@ -1,7 +1,7 @@ #ifndef _ddekit_print_h #define _ddekit_print_h -#include +#include "c_headers.h" /** Print message. * \ingroup DDEKit_util 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 + +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); +} -- cgit v1.2.3 From 7460caca37c30536b7b507d141cf5b7c51697cf3 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 1 Jan 2010 14:54:28 +0100 Subject: Remove c_headers.h --- libddekit/Makefile | 2 +- libddekit/c_headers.h | 7 ------- libddekit/include/ddekit/panic.h | 19 ++----------------- libddekit/include/ddekit/printf.h | 2 +- libddekit/memory.c | 2 ++ libddekit/timer.c | 1 + 6 files changed, 7 insertions(+), 26 deletions(-) delete mode 100644 libddekit/c_headers.h (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index 018d67c9..4d5d58fa 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -20,7 +20,7 @@ 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 \ + pci.c pgtab.c printf.c resources.c list.c panic.c \ thread.c timer.c kmem.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ include/ddekit/semaphore.h include/ddekit/debug.h \ diff --git a/libddekit/c_headers.h b/libddekit/c_headers.h deleted file mode 100644 index 6141e900..00000000 --- a/libddekit/c_headers.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __C_HEADERS_H__ -#define __C_HEADERS_H__ - -#include -#include - -#endif diff --git a/libddekit/include/ddekit/panic.h b/libddekit/include/ddekit/panic.h index f036ab3e..1468675f 100644 --- a/libddekit/include/ddekit/panic.h +++ b/libddekit/include/ddekit/panic.h @@ -3,29 +3,14 @@ /** \defgroup DDEKit_util */ -#include "c_headers.h" - /** Panic - print error message and enter the kernel debugger. * \ingroup DDEKit_util */ -#define ddekit_panic(format, ...) do \ -{ \ - char buf[1024]; \ - snprintf (buf, 1024, "%s", format); \ - fprintf (stderr , buf, ## __VA_ARGS__); \ - fflush (stderr); \ - abort (); \ -} while (0) +void ddekit_panic(char *fmt, ...) __attribute__((noreturn)); /** Print a debug message. * \ingroup DDEKit_util */ -#define ddekit_debug(format, ...) do \ -{ \ - char buf[1024]; \ - snprintf (buf, 1024, "%s: %s\n", __func__, format); \ - fprintf (stderr , buf, ## __VA_ARGS__); \ - fflush (stderr); \ -} while (0) +void ddekit_debug(char *fmt, ...); #endif diff --git a/libddekit/include/ddekit/printf.h b/libddekit/include/ddekit/printf.h index aa086c71..35b0dfa1 100644 --- a/libddekit/include/ddekit/printf.h +++ b/libddekit/include/ddekit/printf.h @@ -1,7 +1,7 @@ #ifndef _ddekit_print_h #define _ddekit_print_h -#include "c_headers.h" +#include /** Print message. * \ingroup DDEKit_util diff --git a/libddekit/memory.c b/libddekit/memory.c index 781a4bae..69088c2a 100644 --- a/libddekit/memory.c +++ b/libddekit/memory.c @@ -10,6 +10,8 @@ * FIXME check thread-safety and add locks where appropriate */ +#include + #include "ddekit/memory.h" #include "ddekit/panic.h" diff --git a/libddekit/timer.c b/libddekit/timer.c index 4944be69..ea66e5f5 100644 --- a/libddekit/timer.c +++ b/libddekit/timer.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "ddekit/lock.h" #include "ddekit/memory.h" -- cgit v1.2.3 From e87cd850f373309c7e71625a60fd0fbed6f16b88 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 1 Jan 2010 14:58:00 +0100 Subject: check in panic.c --- libddekit/panic.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 libddekit/panic.c (limited to 'libddekit') 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 +#include + +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()"); +} + -- cgit v1.2.3 From f3b3a2ca7ee85517888940a35e652325fa38293f Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 5 Jan 2010 16:07:54 +0100 Subject: Declare fetch_jiffies in the header file. --- libddekit/include/ddekit/timer.h | 1 + 1 file changed, 1 insertion(+) (limited to 'libddekit') diff --git a/libddekit/include/ddekit/timer.h b/libddekit/include/ddekit/timer.h index c0bea6bf..435ba8aa 100644 --- a/libddekit/include/ddekit/timer.h +++ b/libddekit/include/ddekit/timer.h @@ -54,5 +54,6 @@ void ddekit_init_timers(void); /** Get the timer thread. */ ddekit_thread_t *ddekit_get_timer_thread(void); +extern long long fetch_jiffies (void); #endif -- cgit v1.2.3 From 100cabe1addab441fbd8a1a023f9ab9956290268 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 13 Jan 2010 12:11:10 +0100 Subject: hide __get_free_pages to avoid name conflict. --- libddekit/kmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/kmem.c b/libddekit/kmem.c index 49b9a9d3..7a35f3d8 100644 --- a/libddekit/kmem.c +++ b/libddekit/kmem.c @@ -78,7 +78,7 @@ struct chunkhdr unsigned long bitmap; /* busy/free bitmap of pages */ }; -unsigned long __get_free_pages (unsigned long order, int dma); +static unsigned long __get_free_pages (unsigned long order, int dma); void free_pages (unsigned long addr, unsigned long order); static struct mutex mem_lock = MUTEX_INITIALIZER; -- cgit v1.2.3 From 74cdae91f9302fbe586dc3ec136a79a7016f4cd7 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 16 Jan 2010 00:04:54 +0100 Subject: Create a ddekit thread directly for ddekit timer. --- libddekit/timer.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'libddekit') diff --git a/libddekit/timer.c b/libddekit/timer.c index ea66e5f5..8ad440c7 100644 --- a/libddekit/timer.c +++ b/libddekit/timer.c @@ -34,7 +34,6 @@ typedef struct _timer static ddekit_timer_t *timer_list = NULL; ///< list of pending timers static ddekit_lock_t timer_lock; ///< lock to access timer_list -static cthread_t timer_thread; ///< 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 @@ -77,7 +76,7 @@ static inline void __notify_timer_thread(void) * XXX: Perhaps we should better assert that there is a timer * thread before allowing users to add a timer. */ - if (timer_thread == NULL) + if (timer_thread_ddekit == NULL) return; ddekit_sem_up(notify_semaphore); @@ -125,7 +124,7 @@ int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout) * necessary to notify the timer thread. */ if (t == timer_list) { - Assert(timer_thread); + Assert(timer_thread_ddekit); __notify_timer_thread(); } @@ -229,7 +228,7 @@ 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); + Assert(ddekit_lock_owner (&timer_lock) == (int) timer_thread_ddekit); if (timer_list && (timer_list->expires <= jiffies)) { @@ -279,8 +278,6 @@ static inline int __timer_sleep(unsigned to) 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); @@ -342,6 +339,6 @@ void ddekit_init_timers(void) + ((long long) tp.tv_usec * HZ) / 1000000; ddekit_lock_init (&timer_lock); - timer_thread = cthread_fork ((cthread_fn_t) ddekit_timer_thread, 0); - cthread_detach (timer_thread); + timer_thread_ddekit = ddekit_thread_create (ddekit_timer_thread, + NULL, "ddekit_timer"); } -- cgit v1.2.3 From 76ab4925b163ee5bf6594c79be063662e2157d00 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 19 Jan 2010 11:21:27 +0100 Subject: Add initcall in ddekit. --- libddekit/Makefile | 2 +- libddekit/include/ddekit/initcall.h | 42 +++++++++++++++++++++++++++++++++++++ libddekit/initcall.c | 27 ++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 libddekit/include/ddekit/initcall.h create mode 100644 libddekit/initcall.c (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index 4d5d58fa..958e67d3 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -21,7 +21,7 @@ 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 kmem.c + thread.c timer.c kmem.c initcall.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ include/ddekit/semaphore.h include/ddekit/debug.h \ include/ddekit/inline.h include/ddekit/panic.h \ diff --git a/libddekit/include/ddekit/initcall.h b/libddekit/include/ddekit/initcall.h new file mode 100644 index 00000000..b503cc6a --- /dev/null +++ b/libddekit/include/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) \ + static 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/initcall.c b/libddekit/initcall.c new file mode 100644 index 00000000..78c24146 --- /dev/null +++ b/libddekit/initcall.c @@ -0,0 +1,27 @@ +#include + +#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 (*const 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++; + } +} + -- cgit v1.2.3 From 86190bc892f3421e0c7a995db5572dd7628b6c43 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 19 Jan 2010 11:44:31 +0100 Subject: hide free_pages. --- libddekit/kmem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/kmem.c b/libddekit/kmem.c index 7a35f3d8..668505ec 100644 --- a/libddekit/kmem.c +++ b/libddekit/kmem.c @@ -79,7 +79,7 @@ struct chunkhdr }; static unsigned long __get_free_pages (unsigned long order, int dma); -void free_pages (unsigned long addr, unsigned long order); +static void free_pages (unsigned long addr, unsigned long order); static struct mutex mem_lock = MUTEX_INITIALIZER; @@ -277,6 +277,8 @@ linux_kmalloc (unsigned int size, int priority) if (pages_free[i].end == 0) break; + // TODO use a dynamically allocated memory to + // record directly allocated large memory. assert (i < MEM_CHUNKS_TOTAL); size = ROUND_UP (size); err = vm_dma_buff_alloc (priv_host, mach_task_self (), size, -- cgit v1.2.3 From d3d72c7fc48e54f9da4ebcfa57f5949b18f5d717 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 21 Jan 2010 09:11:46 +0100 Subject: initialize pciaccess in ddekit. --- libddekit/pci.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'libddekit') diff --git a/libddekit/pci.c b/libddekit/pci.c index 5c3f4ef6..5c0c0ae2 100644 --- a/libddekit/pci.c +++ b/libddekit/pci.c @@ -1,4 +1,5 @@ #include +#include #include #include "ddekit/assert.h" @@ -37,9 +38,14 @@ void ddekit_pci_init(void) { int slots_found = 0; int i; + 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"); + /* Init device list */ for (i = 0; i < MAX_PCI_DEVS; i++) ddekit_pci_bus[i].slot = -1; -- cgit v1.2.3 From ed60ecf7abdade8ee7b63f7621b3920ca9c42912 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 26 Jan 2010 08:54:41 +0100 Subject: ddekit: support multiple pci buses in the system. --- libddekit/pci.c | 106 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 41 deletions(-) (limited to 'libddekit') diff --git a/libddekit/pci.c b/libddekit/pci.c index 5c0c0ae2..ca16b6f9 100644 --- a/libddekit/pci.c +++ b/libddekit/pci.c @@ -1,5 +1,6 @@ #include #include +#include #include #include "ddekit/assert.h" @@ -9,22 +10,26 @@ #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 */ struct pci_device *dev; - struct ddekit_pci_dev *next; /**< chaining info */ } ddekit_pci_dev_t; -static ddekit_pci_dev_t ddekit_pci_bus[MAX_PCI_DEVS]; +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->slot == -1; + return d->dev == NULL; } @@ -37,7 +42,6 @@ static inline int invalid_device(ddekit_pci_dev_t *d) void ddekit_pci_init(void) { int slots_found = 0; - int i; int err; struct pci_device *pci_dev; struct pci_device_iterator *dev_iter; @@ -46,25 +50,35 @@ void ddekit_pci_init(void) if (err) error (2, err, "pci_system_init"); - /* Init device list */ - for (i = 0; i < MAX_PCI_DEVS; i++) - ddekit_pci_bus[i].slot = -1; - + 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) { - if (slots_found == MAX_PCI_DEVS) { - ddekit_printf ("find more than %d pci devices", - slots_found); - break; + /* 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); } - /* 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].dev = pci_dev; - + 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); } @@ -80,11 +94,12 @@ int ddekit_pci_get_device(int nr, int *bus, int *slot, int *func) ddekit_printf ("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; + 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; } @@ -99,19 +114,17 @@ ddekit_pci_dev_t *ddekit_pci_find_device(int *bus, int *slot, int *func, Assert(slot); Assert(func); - ddekit_printf ("start %p (slot %d)", - start, start ? start->slot : -1); - int idx = start ? start->slot + 1 : 0; + int idx = start ? start->dev->dev + 1 : 0; - for ( ; idx < MAX_PCI_DEVS; ++idx) { - ddekit_pci_dev_t *dev = &ddekit_pci_bus[idx]; + 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->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; + (*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; } } @@ -160,7 +173,16 @@ int ddekit_pci_write(int bus, int slot, int func, int pos, int len, ddekit_uint3 */ static inline ddekit_pci_dev_t *ddekit_pci_find_device_fixed(int bus, int slot, int func) { - return &ddekit_pci_bus[slot]; + 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; } @@ -187,8 +209,10 @@ int ddekit_pci_readw (int bus, int slot, int func, int pos, ddekit_uint16_t *val 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) + if (dev) { + assert (dev->dev != NULL); return pci_device_cfg_read_u32 (dev->dev, val, pos); + } else return -1; } -- cgit v1.2.3 From ff4e243b5be3be650e554a795e54ea428bcaea20 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 26 Jan 2010 09:12:56 +0100 Subject: raise the priority of the interrupt handler thread. --- libddekit/interrupt.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'libddekit') diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index 5a778f9b..f3fc10c0 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -60,6 +60,7 @@ static struct } ddekit_irq_ctrl[MAX_INTERRUPTS]; static mach_port_t master_device; +static mach_port_t master_host; /** * Interrupt service loop @@ -69,11 +70,19 @@ static void intloop(void *arg) { kern_return_t ret; struct intloop_params *params = arg; - mach_port_t delivery_port = mach_reply_port (); + mach_port_t delivery_port = mach_port_reply (); + mach_port_t pset, psetcntl; int my_index; 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"); @@ -257,7 +266,7 @@ void interrupt_init () error_t err; - err = get_privileged_ports (0, &master_device); + err = get_privileged_ports (&master_host, &master_device); if (err) error (1, err, "get_privileged_ports"); } -- cgit v1.2.3 From 7f5f5b2136c00c122bc543407f96a890425d32cb Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 26 Jan 2010 09:14:06 +0100 Subject: allocate a port for interrupt delivery. --- libddekit/interrupt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index f3fc10c0..e41a6a68 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -70,10 +70,15 @@ static void intloop(void *arg) { kern_return_t ret; struct intloop_params *params = arg; - mach_port_t delivery_port = mach_port_reply (); + 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); -- cgit v1.2.3 From 9a4c7042e2c9cb3ad993b4c80206d1a01a4f154a Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 27 Jan 2010 09:25:39 +0100 Subject: Enable the irq after installing irq handler and receiving an interrupt. --- libddekit/interrupt.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'libddekit') diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index e41a6a68..f92e36c9 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -103,6 +103,7 @@ static void intloop(void *arg) params->start_err = ret; ddekit_sem_up(params->started); } + device_irq_enable (master_device, params->irq, TRUE); #if 0 /* @@ -140,6 +141,9 @@ static void intloop(void *arg) ddekit_printf ("IRQ %x, handler %p", my_index,params->handler); params->handler(params->priv); + /* If the irq has been disabled by the linux device, + * we don't need to reenable the real one. */ + device_irq_enable (master_device, my_index, TRUE); } else ddekit_printf ("not handling IRQ %x, because it is disabled.", -- cgit v1.2.3 From 411212770f0b499f34d0244b84dadfe08241768c Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 27 Jan 2010 09:27:22 +0100 Subject: remove the printing in timer. --- libddekit/timer.c | 1 - 1 file changed, 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/timer.c b/libddekit/timer.c index 8ad440c7..cbd11522 100644 --- a/libddekit/timer.c +++ b/libddekit/timer.c @@ -89,7 +89,6 @@ int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout) ddekit_timer_t *t = ddekit_simple_malloc(sizeof(ddekit_timer_t)); Assert(t); - printf ("add a timer at %ld\n", timeout); /* fill in values */ t->fn = fn; -- cgit v1.2.3 From 3f46d3b565db7c4a88e6484fc8022d4fff1c65e3 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 29 Jan 2010 19:56:48 +0100 Subject: remove printing in the interrupt handler. --- libddekit/interrupt.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'libddekit') diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index f92e36c9..8590a85c 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -138,8 +138,6 @@ static void intloop(void *arg) /* only call registered handler function, if IRQ is not disabled */ ddekit_lock_lock (&ddekit_irq_ctrl[my_index].irqlock); if (ddekit_irq_ctrl[my_index].handle_irq > 0) { - ddekit_printf ("IRQ %x, handler %p", - my_index,params->handler); params->handler(params->priv); /* If the irq has been disabled by the linux device, * we don't need to reenable the real one. */ -- cgit v1.2.3 From 21584dfe2bc05df7bc5109c3baeb0d4c794f3099 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 5 Feb 2010 14:37:33 +0100 Subject: fix a bug in ddekit: use the relative time. --- libddekit/thread.c | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) (limited to 'libddekit') diff --git a/libddekit/thread.c b/libddekit/thread.c index 34a293e1..10b86de8 100644 --- a/libddekit/thread.c +++ b/libddekit/thread.c @@ -292,33 +292,12 @@ void ddekit_init_threads() { /* Block THREAD. */ static error_t _timedblock (struct _ddekit_private_data *data, - const struct timespec *abstime) + const int timeout) { error_t err; mach_msg_header_t msg; - mach_msg_timeout_t timeout; - struct timeval now; - /* We have an absolute time and now we have to convert it to a - relative time. Arg. */ - - err = gettimeofday(&now, NULL); - assert (! err); - - if (now.tv_sec > abstime->tv_sec - || (now.tv_sec == abstime->tv_sec - && now.tv_usec > ((abstime->tv_nsec + 999) / 1000))) - return ETIMEDOUT; - - timeout = (abstime->tv_sec - now.tv_sec) * 1000; - - if (((abstime->tv_nsec + 999) / 1000) >= now.tv_usec) - timeout -= (((abstime->tv_nsec + 999) / 1000) - - now.tv_usec + 999) / 1000; - else - /* Need to do a carry. */ - timeout -= 1000 + ((abstime->tv_nsec + 999999) / 1000000) - - (now.tv_usec + 999) / 1000; + assert (timeout > 0); err = mach_msg (&msg, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, sizeof msg, data->wakeupmsg.msgh_remote_port, @@ -343,7 +322,7 @@ static void _block (struct _ddekit_private_data *data) } static int _sem_timedwait_internal (ddekit_sem_t *restrict sem, - const struct timespec *restrict timeout) + const int timeout) { struct _ddekit_private_data *self_private_data; @@ -355,8 +334,7 @@ static int _sem_timedwait_internal (ddekit_sem_t *restrict sem, return 0; } - if (timeout && (timeout->tv_nsec < 0 - || timeout->tv_nsec >= 1000000000)) { + if (timeout < 0) { errno = EINVAL; return -1; } @@ -428,7 +406,7 @@ void ddekit_sem_deinit(ddekit_sem_t *sem) { } void ddekit_sem_down(ddekit_sem_t *sem) { - _sem_timedwait_internal (sem, NULL); + _sem_timedwait_internal (sem, 0); } /* returns 0 on success, != 0 when it would block */ @@ -448,11 +426,7 @@ int ddekit_sem_down_try(ddekit_sem_t *sem) { /* returns 0 on success, != 0 on timeout */ int ddekit_sem_down_timed(ddekit_sem_t *sem, int timo) { /* wait for up to timo milliseconds */ - struct timespec timeout; - - timeout.tv_sec = timo / 1000; - timeout.tv_nsec = (timo % 1000) * 1000 * 1000; - return _sem_timedwait_internal (sem, &timeout); + return _sem_timedwait_internal (sem, timo); } void ddekit_sem_up(ddekit_sem_t *sem) { -- cgit v1.2.3 From db1709c923475daedc00424824bb5e6094bc09f7 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 5 Feb 2010 14:38:12 +0100 Subject: print to stderr. --- libddekit/printf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/printf.c b/libddekit/printf.c index a35c4bc9..dacc65e6 100644 --- a/libddekit/printf.c +++ b/libddekit/printf.c @@ -74,7 +74,7 @@ int ddekit_vprintf(const char *fmt, va_list va) int log_init () { if (using_std) { - output = stdout; + output = stderr; } else { char template[] = "/var/log/dde_log.XXXXXX"; -- cgit v1.2.3 From 1c3c575b2324f666b816164afe3a100896b81840 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 27 Feb 2010 14:14:02 +0100 Subject: remove RPCs for PCI conf space. --- libddekit/device.defs | 38 -------------------------------------- libmachdev/device.defs | 39 --------------------------------------- libmachdev/ds_routines.c | 29 ----------------------------- 3 files changed, 106 deletions(-) (limited to 'libddekit') diff --git a/libddekit/device.defs b/libddekit/device.defs index 6a73853a..07ff58f6 100644 --- a/libddekit/device.defs +++ b/libddekit/device.defs @@ -157,44 +157,6 @@ routine device_intr_notify( in receive_port : mach_port_send_t ); -/* - * Test whether IPC devices exist. - */ -routine pci_present( - master_port : mach_port_t); - -/* - * Find the specified PCI device. - */ -routine pci_find_device( - master_port : mach_port_t; - vendor : short; - device_id : short; - index : short; - out bus : char; - out device_fn : char); - -/* - * Read the configuration space of a IPC device. - */ -routine pci_read_config( - master_port : mach_port_t; - bus : char; - device_fn : char; - where : char; - bytes_wanted : int; - out result : pci_config_data_t); - -/* - * Write the configuration space of a IPC device. - */ -routine pci_write_config( - master_port : mach_port_t; - bus : char; - device_fn : char; - where : char; - data : pci_config_data_t); - /* * enable/disable the specified irq. */ diff --git a/libmachdev/device.defs b/libmachdev/device.defs index 6a73853a..b514b3b9 100644 --- a/libmachdev/device.defs +++ b/libmachdev/device.defs @@ -48,7 +48,6 @@ subsystem serverprefix ds_; -type pci_config_data_t = array[*:4] of char; type reply_port_t = MACH_MSG_TYPE_MAKE_SEND_ONCE | polymorphic ctype: mach_port_t; @@ -157,44 +156,6 @@ routine device_intr_notify( in receive_port : mach_port_send_t ); -/* - * Test whether IPC devices exist. - */ -routine pci_present( - master_port : mach_port_t); - -/* - * Find the specified PCI device. - */ -routine pci_find_device( - master_port : mach_port_t; - vendor : short; - device_id : short; - index : short; - out bus : char; - out device_fn : char); - -/* - * Read the configuration space of a IPC device. - */ -routine pci_read_config( - master_port : mach_port_t; - bus : char; - device_fn : char; - where : char; - bytes_wanted : int; - out result : pci_config_data_t); - -/* - * Write the configuration space of a IPC device. - */ -routine pci_write_config( - master_port : mach_port_t; - bus : char; - device_fn : char; - where : char; - data : pci_config_data_t); - /* * enable/disable the specified irq. */ diff --git a/libmachdev/ds_routines.c b/libmachdev/ds_routines.c index 857f64c5..1961a2f3 100644 --- a/libmachdev/ds_routines.c +++ b/libmachdev/ds_routines.c @@ -154,35 +154,6 @@ ds_device_intr_notify (mach_port_t master_port, int irq, return D_INVALID_OPERATION; } -kern_return_t -ds_pci_write_config (mach_port_t master_port, char bus, char device_fn, - char where, pci_config_data_t data, - mach_msg_type_number_t dataCnt) -{ - return D_INVALID_OPERATION; -} - -kern_return_t -ds_pci_read_config (mach_port_t master_port, char bus, char device_fn, - char where, int bytes_wanted, pci_config_data_t result, - mach_msg_type_number_t *resultCnt) -{ - return D_INVALID_OPERATION; -} - -kern_return_t -ds_pci_find_device (mach_port_t master_port, short vendor, short device_id, - short index, short *bus, char *device_fn) -{ - return D_INVALID_OPERATION; -} - -kern_return_t -ds_pci_present (mach_port_t master_port) -{ - return D_INVALID_OPERATION; -} - kern_return_t ds_device_irq_enable (mach_port_t master_port, int irq, char status) -- cgit v1.2.3 From 5b14fbc2aeedc2501b032d8ea6b4b68eafaf321b Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 27 Feb 2010 14:19:29 +0100 Subject: Add `flags` for interrupt registration. --- libddekit/interrupt.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'libddekit') diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index 8590a85c..09117732 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -92,10 +92,11 @@ static void intloop(void *arg) if (ret) error (0, ret, "thread_priority"); - // TODO I should give another parameter to show whether - // the interrupt can be shared. + // 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_notify (master_device, params->irq, - 0, delivery_port, + 0, 0x04000000, delivery_port, MACH_MSG_TYPE_MAKE_SEND); if (!ret) { /* inform thread creator of error */ -- cgit v1.2.3 From 9c9e0b826cc986dea7a6f1d6cc331c37ed9b469d Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 27 Feb 2010 14:43:24 +0100 Subject: Add `flags` in RPC device_intr_notify definition. --- libddekit/device.defs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/device.defs b/libddekit/device.defs index 07ff58f6..ef777efe 100644 --- a/libddekit/device.defs +++ b/libddekit/device.defs @@ -48,7 +48,6 @@ subsystem serverprefix ds_; -type pci_config_data_t = array[*:4] of char; type reply_port_t = MACH_MSG_TYPE_MAKE_SEND_ONCE | polymorphic ctype: mach_port_t; @@ -154,6 +153,7 @@ routine device_intr_notify( master_port : mach_port_t; in irq : int; in id : int; + in flags : int; in receive_port : mach_port_send_t ); -- cgit v1.2.3 From 44f34a7ad2d0c21621d5b9f8004af0dc0dcadffe Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 27 Feb 2010 14:47:02 +0100 Subject: IRQ server doesn't have reply messages. --- libddekit/interrupt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'libddekit') diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index 09117732..540be846 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -126,6 +126,7 @@ static void intloop(void *arg) int irq_server (mach_msg_header_t *inp, mach_msg_header_t *outp) { mach_irq_notification_t *irq_header = (mach_irq_notification_t *) inp; + ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY; if (inp->msgh_id != MACH_NOTIFY_IRQ) return 0; @@ -148,8 +149,6 @@ static void intloop(void *arg) ddekit_printf ("not handling IRQ %x, because it is disabled.", my_index); - // ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY; - if (ddekit_irq_ctrl[my_index].thread_exit) { ddekit_lock_unlock (&ddekit_irq_ctrl[my_index].irqlock); ddekit_thread_exit(); -- cgit v1.2.3 From 7634fec1207d53f452a257c9cb0fc4986a211709 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 28 Feb 2010 05:29:56 +0100 Subject: reset the helder pointer before unlock in ddekit lock. I don't know if it helps fix any bugs, but it should be a right thing to do. --- libddekit/lock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/lock.c b/libddekit/lock.c index 4c4cff01..e534bebe 100644 --- a/libddekit/lock.c +++ b/libddekit/lock.c @@ -39,9 +39,9 @@ int _ddekit_lock_try_lock(struct ddekit_lock **mtx) { } void _ddekit_lock_unlock(struct ddekit_lock **mtx) { - mutex_unlock (&(*mtx)->lock); // TODO I wonder if it can cause any trouble. (*mtx)->helder = NULL; + mutex_unlock (&(*mtx)->lock); } -- cgit v1.2.3 From de9ae8c5bb5e3a74f27e8e2036c9baa771a60795 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 3 Mar 2010 12:35:45 +0100 Subject: Support MMIO. --- libddekit/resources.c | 76 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 13 deletions(-) (limited to 'libddekit') diff --git a/libddekit/resources.c b/libddekit/resources.c index 4bbd2db9..8303af15 100644 --- a/libddekit/resources.c +++ b/libddekit/resources.c @@ -1,4 +1,8 @@ +#include #include +#include +#include +#include #include "ddekit/resources.h" @@ -36,6 +40,36 @@ 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, "iopl", &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 @@ -43,17 +77,30 @@ int ddekit_release_io(ddekit_addr_t start, ddekit_addr_t count) { * \return -1 error */ int ddekit_request_mem(ddekit_addr_t start, ddekit_addr_t count, ddekit_addr_t *vaddr) { -#if 0 - ddekit_addr_t v; + memory_object_t iopl_mem; + kern_return_t err; + *vaddr = 0; + + iopl_mem = get_physmem_object(); - v = l4io_request_mem_region(start, count, 0); - if (v) { - *vaddr = v; - return 0; - } else + 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; -#endif - return -1; + } + return 0; } /** Release memory region. @@ -62,8 +109,11 @@ int ddekit_request_mem(ddekit_addr_t start, ddekit_addr_t count, ddekit_addr_t * * \return <0 error */ int ddekit_release_mem(ddekit_addr_t start, ddekit_addr_t count) { -#if 0 - return l4io_release_mem_region(start, count); -#endif - return -1; + 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; } -- cgit v1.2.3 From 405f510fe09f80213e26c89bb365beaedeca3ad2 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 6 Apr 2010 04:31:12 +0200 Subject: Use mem device to map memory for MMIO. --- libddekit/resources.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/resources.c b/libddekit/resources.c index 8303af15..212dcae7 100644 --- a/libddekit/resources.c +++ b/libddekit/resources.c @@ -54,7 +54,7 @@ static memory_object_t get_physmem_object(void) 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, "iopl", &iopl_dev); + 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"); -- cgit v1.2.3 From d31e486426aed7952b3468a63f2e81735d09943c Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 6 Apr 2010 04:33:16 +0200 Subject: implement dump_stack in libddekit with backtrace. --- libdde_linux26/lib/src/arch/l4/process.c | 4 ---- libddekit/include/ddekit/printf.h | 2 ++ libddekit/printf.c | 12 ++++++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) (limited to 'libddekit') diff --git a/libdde_linux26/lib/src/arch/l4/process.c b/libdde_linux26/lib/src/arch/l4/process.c index b5189cd4..ac700f82 100644 --- a/libdde_linux26/lib/src/arch/l4/process.c +++ b/libdde_linux26/lib/src/arch/l4/process.c @@ -220,10 +220,6 @@ void do_exit(long code) ** Misc functions ** *****************************************************************************/ -void dump_stack(void) -{ -} - char *get_task_comm(char *buf, struct task_struct *tsk) { diff --git a/libddekit/include/ddekit/printf.h b/libddekit/include/ddekit/printf.h index 35b0dfa1..6dafa18d 100644 --- a/libddekit/include/ddekit/printf.h +++ b/libddekit/include/ddekit/printf.h @@ -18,6 +18,8 @@ int ddekit_printf(const char *fmt, ...); */ int ddekit_vprintf(const char *fmt, va_list va); +void dump_stack(void); + /** Log function and message. * \ingroup DDEKit_util */ diff --git a/libddekit/printf.c b/libddekit/printf.c index dacc65e6..c4a8b718 100644 --- a/libddekit/printf.c +++ b/libddekit/printf.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "ddekit/printf.h" @@ -93,3 +94,14 @@ int log_init () 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); +} -- cgit v1.2.3 From b168f41d6eab6319bb5a2fcc065541ba2b18926e Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 22 Apr 2010 15:07:28 +0200 Subject: jiffies in the type of unsigned long. --- libddekit/include/ddekit/timer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/include/ddekit/timer.h b/libddekit/include/ddekit/timer.h index 435ba8aa..387f2078 100644 --- a/libddekit/include/ddekit/timer.h +++ b/libddekit/include/ddekit/timer.h @@ -54,6 +54,6 @@ void ddekit_init_timers(void); /** Get the timer thread. */ ddekit_thread_t *ddekit_get_timer_thread(void); -extern long long fetch_jiffies (void); +extern unsigned long fetch_jiffies (void); #endif -- cgit v1.2.3 From 13bb1a10037412c0a232f69e5dcf80b62dc90b13 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 22 Apr 2010 15:09:38 +0200 Subject: jiffies in the type of unsigned long. --- libddekit/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/timer.c b/libddekit/timer.c index cbd11522..a8a91a85 100644 --- a/libddekit/timer.c +++ b/libddekit/timer.c @@ -54,7 +54,7 @@ static void dump_list(char *msg) #endif } -long long fetch_jiffies () +unsigned long fetch_jiffies () { struct timeval tv; long long j; -- cgit v1.2.3 From 589e5402f5e90286019e33f11cdc00429f01cca8 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 22 Apr 2010 15:12:46 +0200 Subject: ddekit: print messages. --- libddekit/Makefile | 2 +- libddekit/kmem.c | 3 ++- libddekit/memory.c | 7 ++++++- libddekit/pgtab.c | 7 ++++++- 4 files changed, 15 insertions(+), 4 deletions(-) (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index 958e67d3..04921b83 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -31,7 +31,7 @@ LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ include/ddekit/interrupt.h include/ddekit/resources.h \ include/ddekit/memory.h include/ddekit/timer.h \ include/dde.h \ - config.h list.h + config.h list.h util.h installhdrs = MIGSTUBS = deviceUser.o machUser.o diff --git a/libddekit/kmem.c b/libddekit/kmem.c index 668505ec..3b869cc9 100644 --- a/libddekit/kmem.c +++ b/libddekit/kmem.c @@ -30,6 +30,7 @@ #include #include +#include "util.h" #include "vm_param.h" #include "ddekit/panic.h" @@ -286,7 +287,7 @@ linux_kmalloc (unsigned int size, int priority) if (!err) pages_free[i].end = pages_free[i].start + size; mutex_unlock (&mem_lock); - printf ("allocate %d bytes at (virt: %x, phys: %x), slot %d\n", + fprintf (stderr, "allocate %d bytes at (virt: %x, phys: %x), slot %d\n", size, pages_free[i].start, pages_free[i].pstart, i); return err ? NULL : (void *) pages_free[i].start; diff --git a/libddekit/memory.c b/libddekit/memory.c index 69088c2a..d7ea9705 100644 --- a/libddekit/memory.c +++ b/libddekit/memory.c @@ -11,7 +11,9 @@ */ #include +#include +#include "util.h" #include "ddekit/memory.h" #include "ddekit/panic.h" @@ -52,7 +54,6 @@ struct ddekit_pcache int contig; }; - /** * Setup page cache for all slabs * @@ -64,6 +65,7 @@ struct ddekit_pcache */ void ddekit_slab_setup_page_cache(unsigned pages) { + UNIMPL; } /******************************* @@ -109,6 +111,7 @@ void ddekit_slab_set_data(struct ddekit_slab * slab, void *data) #if 0 l4slab_set_data(&slab->cache, data); #endif + UNIMPL; } @@ -120,6 +123,7 @@ void *ddekit_slab_get_data(struct ddekit_slab * slab) #if 0 return l4slab_get_data(&slab->cache); #endif + UNIMPL; return NULL; } @@ -179,6 +183,7 @@ void ddekit_large_free(void *objp) */ void *ddekit_large_malloc(int size) { + ddekit_printf("ddekit_large_malloc %d bytes\n", size); return linux_kmalloc (size, 0); } diff --git a/libddekit/pgtab.c b/libddekit/pgtab.c index 88273b7c..aa652c75 100644 --- a/libddekit/pgtab.c +++ b/libddekit/pgtab.c @@ -14,7 +14,7 @@ #include #include "ddekit/pgtab.h" - +#include "util.h" #include "config.h" /***************************** @@ -59,6 +59,7 @@ int ddekit_pgtab_get_type(const void *virtual) return p->type; #endif + UNIMPL; return 0; } @@ -76,6 +77,7 @@ int ddekit_pgtab_get_size(const void *virtual) return p->size; #endif + UNIMPL; return 0; } @@ -88,6 +90,7 @@ int ddekit_pgtab_get_size(const void *virtual) */ void ddekit_pgtab_clear_region(void *virtual, int type) { + UNIMPL; } @@ -101,9 +104,11 @@ void ddekit_pgtab_clear_region(void *virtual, int type) */ void ddekit_pgtab_set_region(void *virtual, ddekit_addr_t physical, int pages, int type) { + UNIMPL; } void ddekit_pgtab_set_region_with_size(void *virt, ddekit_addr_t phys, int size, int type) { + UNIMPL; } -- cgit v1.2.3 From 1debf236297c125504b0c163cbf8e4095d053ff7 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 4 May 2010 16:10:38 +0200 Subject: Use more memory chunks for linux_kmalloc. --- libddekit/kmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/kmem.c b/libddekit/kmem.c index 3b869cc9..cea4d370 100644 --- a/libddekit/kmem.c +++ b/libddekit/kmem.c @@ -43,7 +43,7 @@ extern int printf (const char *, ...); We reserve 64K chunks to stay within DMA limits. Increase MEM_CHUNKS if the kernel is running out of memory. */ #define MEM_CHUNK_SIZE (64 * 1024) -#define MEM_CHUNKS 7 +#define MEM_CHUNKS 30 #define MEM_CHUNKS_TOTAL (MEM_CHUNKS + 5) /* round up the size at alignment of page size. */ -- cgit v1.2.3 From 269e296815b7ad2010097a28583f698ad4ce6554 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 4 May 2010 16:15:34 +0200 Subject: Add util.h in libddekit. --- libddekit/util.h | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 libddekit/util.h (limited to 'libddekit') 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 -- cgit v1.2.3 From a3ceae18db61ff5dd7d86a79d794f992d58604f4 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 7 May 2010 01:15:03 +0000 Subject: fix a bug when device_intr_notify return an error. --- libddekit/interrupt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index 540be846..8cf4bee1 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -98,11 +98,14 @@ static void intloop(void *arg) ret = device_intr_notify (master_device, params->irq, 0, 0x04000000, delivery_port, MACH_MSG_TYPE_MAKE_SEND); - if (!ret) { + ddekit_printf ("device_intr_notify 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_irq_enable (master_device, params->irq, TRUE); -- cgit v1.2.3 From fd11239e5a0f745cf40f954f772ed7dcdf95d018 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 7 May 2010 16:56:28 +0000 Subject: call device_irq_enable even when interrupt is ignored. --- libddekit/interrupt.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'libddekit') diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index 8cf4bee1..6f7755ad 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -144,13 +144,10 @@ static void intloop(void *arg) ddekit_lock_lock (&ddekit_irq_ctrl[my_index].irqlock); if (ddekit_irq_ctrl[my_index].handle_irq > 0) { params->handler(params->priv); - /* If the irq has been disabled by the linux device, - * we don't need to reenable the real one. */ - device_irq_enable (master_device, my_index, TRUE); } - else - ddekit_printf ("not handling IRQ %x, because it is disabled.", - my_index); + /* If the irq has been disabled by the linux device, + * we don't need to reenable the real one. */ + device_irq_enable (master_device, my_index, TRUE); if (ddekit_irq_ctrl[my_index].thread_exit) { ddekit_lock_unlock (&ddekit_irq_ctrl[my_index].irqlock); -- cgit v1.2.3 From 3b52d15454648a6ec01bd595cc58c52bb1457ad0 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 11 May 2010 04:33:47 +0000 Subject: block intloop thread when irq is disabled. --- libddekit/interrupt.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'libddekit') diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index 6f7755ad..5a545f5a 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -17,6 +17,7 @@ #include "ddekit/semaphore.h" #include "ddekit/printf.h" #include "ddekit/memory.h" +#include "ddekit/condvar.h" #include "device_U.h" @@ -54,6 +55,7 @@ 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; @@ -142,9 +144,12 @@ static void intloop(void *arg) /* only call registered handler function, if IRQ is not disabled */ ddekit_lock_lock (&ddekit_irq_ctrl[my_index].irqlock); - if (ddekit_irq_ctrl[my_index].handle_irq > 0) { - params->handler(params->priv); + 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_irq_enable (master_device, my_index, TRUE); @@ -214,6 +219,7 @@ ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, ddekit_irq_ctrl[irq].handle_irq = 1; /* IRQ nesting level is initially 1 */ ddekit_irq_ctrl[irq].irq_thread = thread; ddekit_lock_init_unlocked (&ddekit_irq_ctrl[irq].irqlock); + ddekit_irq_ctrl[irq].cond = ddekit_condvar_init (); ddekit_irq_ctrl[irq].thread_exit = FALSE; @@ -235,6 +241,7 @@ ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, 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; @@ -264,6 +271,8 @@ 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); } } -- cgit v1.2.3 From ff4ec384e4688dfb09286eef763a173ef54ce80a Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 28 May 2010 12:20:06 +0200 Subject: memory from linux_kmalloc is aligned with cache line size. It's an ugly fix. --- libddekit/kmem.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'libddekit') diff --git a/libddekit/kmem.c b/libddekit/kmem.c index cea4d370..570c1f53 100644 --- a/libddekit/kmem.c +++ b/libddekit/kmem.c @@ -49,8 +49,9 @@ extern int printf (const char *, ...); /* round up the size at alignment of page size. */ #define ROUND_UP(size) ((size) + __vm_page_size - 1) & (~(__vm_page_size - 1)) +#define CACHE_LINE 32 /* Mininum amount that linux_kmalloc will allocate. */ -#define MIN_ALLOC 12 +#define MIN_ALLOC CACHE_LINE #ifndef NBPW #define NBPW 32 @@ -61,6 +62,7 @@ struct blkhdr { unsigned short free; /* 1 if block is free */ unsigned short size; /* size of block */ + char stuffing[28]; }; /* This structure heads a page allocated by linux_kmalloc. */ @@ -68,6 +70,7 @@ struct pagehdr { unsigned size; /* size (multiple of PAGE_SIZE) */ struct pagehdr *next; /* next header in list */ + char stuffing[24]; }; /* This structure describes a memory chunk. */ @@ -263,7 +266,7 @@ linux_kmalloc (unsigned int size, int priority) if (size < MIN_ALLOC) size = MIN_ALLOC; else - size = (size + sizeof (int) - 1) & ~(sizeof (int) - 1); + size = (size + CACHE_LINE - 1) & ~(CACHE_LINE - 1); mutex_lock (&mem_lock); -- cgit v1.2.3 From f04e8156038d62d6a79e05d9b022c53705e44048 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 28 May 2010 15:01:57 +0200 Subject: reimplement ddekit_large_malloc. --- libddekit/memory.c | 31 +++++++++++-- libddekit/pgtab.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 142 insertions(+), 18 deletions(-) (limited to 'libddekit') diff --git a/libddekit/memory.c b/libddekit/memory.c index d7ea9705..03752211 100644 --- a/libddekit/memory.c +++ b/libddekit/memory.c @@ -12,10 +12,16 @@ #include #include +#include +#include +#include +#include +#include "mach_U.h" #include "util.h" #include "ddekit/memory.h" #include "ddekit/panic.h" +#include "ddekit/pgtab.h" extern void * linux_kmalloc (unsigned int size, int priority); extern void linux_kfree (void *p); @@ -172,7 +178,12 @@ struct ddekit_slab * ddekit_slab_init(unsigned size, int contiguous) */ void ddekit_large_free(void *objp) { - linux_kfree (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"); } @@ -183,8 +194,22 @@ void ddekit_large_free(void *objp) */ void *ddekit_large_malloc(int size) { - ddekit_printf("ddekit_large_malloc %d bytes\n", size); - return linux_kmalloc (size, 0); + error_t err; + vm_address_t vstart, pstart; + extern mach_port_t priv_host; + + /* Allocate memory. */ + err = vm_dma_buff_alloc (priv_host, mach_task_self (), + size, &vstart, &pstart); + if (err) + { + error (0, err, "vm_dma_buff_alloc"); + vstart = 0; + } + else + ddekit_pgtab_set_region_with_size ((void *) vstart, pstart, size, 0); + + return (void *) vstart; } diff --git a/libddekit/pgtab.c b/libddekit/pgtab.c index aa652c75..35cc630a 100644 --- a/libddekit/pgtab.c +++ b/libddekit/pgtab.c @@ -11,16 +11,64 @@ * For this to work, dataspaces must be attached to l4rm regions! */ +#include +#include +#include #include +#include #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 struct mutex 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 ®ions[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 ®ions[i]; + } + return NULL; +} + /** * Get physical address for virtual address * @@ -29,6 +77,17 @@ */ ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virtual) { + struct entry *e; + mutex_lock (&lock); + e = get_entry_from_virt ((ddekit_addr_t) virtual); + if (e) + { + ddekit_addr_t phys = e->physical; + mutex_unlock (&lock); + return phys; + } + mutex_unlock (&lock); + extern int virt_to_phys (vm_address_t addr); return virt_to_phys ((vm_address_t) virtual); } @@ -41,6 +100,18 @@ ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virtual) */ ddekit_addr_t ddekit_pgtab_get_virtaddr(const ddekit_addr_t physical) { + struct entry *e; + + mutex_lock (&lock); + e = get_entry_from_phys (physical); + if (e) + { + ddekit_addr_t virt = (ddekit_addr_t) e->virtual; + mutex_unlock (&lock); + return virt; + } + mutex_unlock (&lock); + extern int phys_to_virt (vm_address_t addr); return phys_to_virt (physical); } @@ -63,21 +134,18 @@ int ddekit_pgtab_get_type(const void *virtual) return 0; } -//TODO int ddekit_pgtab_get_size(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; + struct entry *e; + mutex_lock (&lock); + e = get_entry_from_virt ((ddekit_addr_t) virtual); + if (e) + { + int size = e->size; + mutex_unlock (&lock); + return size; } - - return p->size; -#endif - UNIMPL; + mutex_unlock (&lock); return 0; } @@ -90,7 +158,16 @@ int ddekit_pgtab_get_size(const void *virtual) */ void ddekit_pgtab_clear_region(void *virtual, int type) { - UNIMPL; + struct entry *e; + + mutex_lock (&lock); + e = get_entry_from_virt ((ddekit_addr_t) virtual); + if (e) + { + *e = regions[num_regions - 1]; + num_regions--; + } + mutex_unlock (&lock); } @@ -104,11 +181,33 @@ void ddekit_pgtab_clear_region(void *virtual, int type) */ void ddekit_pgtab_set_region(void *virtual, ddekit_addr_t physical, int pages, int type) { - UNIMPL; + 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) { - UNIMPL; + 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++; + mutex_unlock (&lock); + ddekit_printf ("******there are %d regions (%d bytes)\n", + num_regions, size); } +int pgtab_init () +{ + capability = INIT_SIZE; + regions = malloc (sizeof (struct entry) * capability); + mutex_init (&lock); + return 0; +} -- cgit v1.2.3 From 2665542c3ad64c96a87712971c588ecd7f510042 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 28 May 2010 16:11:56 +0200 Subject: ddekit slab uses libhurd-slab. --- libddekit/Makefile | 4 +- libddekit/init.c | 14 +- libddekit/kmem.c | 546 ----------------------------------------------------- libddekit/memory.c | 53 ++++-- libddekit/pgtab.c | 14 +- 5 files changed, 59 insertions(+), 572 deletions(-) delete mode 100644 libddekit/kmem.c (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index 04921b83..f0f6be87 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -21,7 +21,7 @@ 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 kmem.c initcall.c + thread.c timer.c initcall.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ include/ddekit/semaphore.h include/ddekit/debug.h \ include/ddekit/inline.h include/ddekit/panic.h \ @@ -37,7 +37,7 @@ installhdrs = MIGSTUBS = deviceUser.o machUser.o OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS)) -HURDLIBS = threads ports shouldbeinlibc +HURDLIBS = threads ports shouldbeinlibc hurd-slab MIGCOMSFLAGS = -prefix dde_ diff --git a/libddekit/init.c b/libddekit/init.c index 9114ff46..7caf4c44 100644 --- a/libddekit/init.c +++ b/libddekit/init.c @@ -3,16 +3,28 @@ * * \author Thomas Friebel */ +#include +#include +#include + #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(); - linux_kmem_init (); + pgtab_init (); log_init (); interrupt_init (); } diff --git a/libddekit/kmem.c b/libddekit/kmem.c deleted file mode 100644 index 570c1f53..00000000 --- a/libddekit/kmem.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * Linux memory allocation. - * - * Copyright (C) 1996 The University of Utah and the Computer Systems - * Laboratory at the University of Utah (CSL) - * - * 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, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Shantanu Goel, University of Utah CSL - * - */ - -#include -#include -#include -#include -#include "mach_U.h" -#include -#include - -#include "util.h" -#include "vm_param.h" - -#include "ddekit/panic.h" - -#define debug ddekit_debug - -extern int printf (const char *, ...); - -/* Amount of memory to reserve for Linux memory allocator. - We reserve 64K chunks to stay within DMA limits. - Increase MEM_CHUNKS if the kernel is running out of memory. */ -#define MEM_CHUNK_SIZE (64 * 1024) -#define MEM_CHUNKS 30 -#define MEM_CHUNKS_TOTAL (MEM_CHUNKS + 5) - -/* round up the size at alignment of page size. */ -#define ROUND_UP(size) ((size) + __vm_page_size - 1) & (~(__vm_page_size - 1)) - -#define CACHE_LINE 32 -/* Mininum amount that linux_kmalloc will allocate. */ -#define MIN_ALLOC CACHE_LINE - -#ifndef NBPW -#define NBPW 32 -#endif - -/* Memory block header. */ -struct blkhdr -{ - unsigned short free; /* 1 if block is free */ - unsigned short size; /* size of block */ - char stuffing[28]; -}; - -/* This structure heads a page allocated by linux_kmalloc. */ -struct pagehdr -{ - unsigned size; /* size (multiple of PAGE_SIZE) */ - struct pagehdr *next; /* next header in list */ - char stuffing[24]; -}; - -/* This structure describes a memory chunk. */ -struct chunkhdr -{ - vm_address_t start; /* start address */ - vm_address_t pstart; /* start physical address */ - vm_address_t end; /* end address */ - unsigned long bitmap; /* busy/free bitmap of pages */ -}; - -static unsigned long __get_free_pages (unsigned long order, int dma); -static void free_pages (unsigned long addr, unsigned long order); - -static struct mutex mem_lock = MUTEX_INITIALIZER; - -/* Chunks from which pages are allocated. - * The extra slots are used to hold the huge chunks (> MEM_CHUNKS_SIZE) - * which are allocated by the user. */ -static struct chunkhdr pages_free[MEM_CHUNKS_TOTAL]; - -/* Memory list maintained by linux_kmalloc. */ -static struct pagehdr *memlist; - -static mach_port_t priv_host; - -/* Some statistics. */ -int num_block_coalesce = 0; -int num_page_collect = 0; -int linux_mem_avail; - -int virt_to_phys (vm_address_t addr) -{ - int i; - - for (i = 0; i < MEM_CHUNKS_TOTAL; i++) - { - if (pages_free[i].start <= addr && pages_free[i].end > addr) - return addr - pages_free[i].start + pages_free[i].pstart; - } - debug ("an address not in any chunks."); - return -1; -} - -int phys_to_virt (vm_address_t addr) -{ -#define CHUNK_SIZE(chunk) ((chunk)->end - (chunk)->start) - int i; - - for (i = 0; i < MEM_CHUNKS_TOTAL; i++) - { - if (pages_free[i].pstart <= addr - && pages_free[i].pstart + CHUNK_SIZE (pages_free + i) > addr) - return addr - pages_free[i].pstart + pages_free[i].start; - } - debug ("an address not in any chunks."); - return -1; -} - -/* Initialize the Linux memory allocator. */ -void -linux_kmem_init () -{ - int i, j; - error_t err; - - err = get_privileged_ports (&priv_host, NULL); - if (err) - error (2, err, "get_privileged_ports"); - - for (i = 0; i < MEM_CHUNKS; i++) - { - error_t err; - - /* Allocate memory. */ - err = vm_dma_buff_alloc (priv_host, mach_task_self (), - MEM_CHUNK_SIZE, &pages_free[i].start, - &pages_free[i].pstart); - if (err) - abort (); - - assert (pages_free[i].start); - - pages_free[i].end = pages_free[i].start + MEM_CHUNK_SIZE; - assert (pages_free[i].pstart + MEM_CHUNK_SIZE <= 16 * 1024 * 1024); - - /* Initialize free page bitmap. */ - pages_free[i].bitmap = 0; - j = MEM_CHUNK_SIZE >> PAGE_SHIFT; - while (--j >= 0) - pages_free[i].bitmap |= 1 << j; - } - - /* Initialize the space for extra slots. */ - memset (pages_free + i, 0, - sizeof (pages_free[0]) * (MEM_CHUNKS_TOTAL - MEM_CHUNKS)); - - linux_mem_avail = (MEM_CHUNKS * MEM_CHUNK_SIZE) >> PAGE_SHIFT; -} - -/* Return the number by which the page size should be - shifted such that the resulting value is >= SIZE. */ -static unsigned long -get_page_order (int size) -{ - unsigned long order; - - for (order = 0; (PAGE_SIZE << order) < size; order++) - ; - return order; -} - -#ifdef LINUX_DEV_DEBUG -static void -check_page_list (int line) -{ - unsigned size; - struct pagehdr *ph; - struct blkhdr *bh; - - for (ph = memlist; ph; ph = ph->next) - { - if ((int) ph & PAGE_MASK) - panic ("%s:%d: page header not aligned", __FILE__, line); - - size = 0; - bh = (struct blkhdr *) (ph + 1); - while (bh < (struct blkhdr *) ((void *) ph + ph->size)) - { - size += bh->size + sizeof (struct blkhdr); - bh = (void *) (bh + 1) + bh->size; - } - - if (size + sizeof (struct pagehdr) != ph->size) - panic ("%s:%d: memory list destroyed", __FILE__, line); - } -} -#else -#define check_page_list(line) -#endif - -/* Merge adjacent free blocks in the memory list. */ -static void -coalesce_blocks () -{ - struct pagehdr *ph; - struct blkhdr *bh, *bhp, *ebh; - - num_block_coalesce++; - - for (ph = memlist; ph; ph = ph->next) - { - bh = (struct blkhdr *) (ph + 1); - ebh = (struct blkhdr *) ((void *) ph + ph->size); - while (1) - { - /* Skip busy blocks. */ - while (bh < ebh && !bh->free) - bh = (struct blkhdr *) ((void *) (bh + 1) + bh->size); - if (bh == ebh) - break; - - /* Merge adjacent free blocks. */ - while (1) - { - bhp = (struct blkhdr *) ((void *) (bh + 1) + bh->size); - if (bhp == ebh) - { - bh = bhp; - break; - } - if (!bhp->free) - { - bh = (struct blkhdr *) ((void *) (bhp + 1) + bhp->size); - break; - } - bh->size += bhp->size + sizeof (struct blkhdr); - } - } - } -} - -/* Allocate SIZE bytes of memory. - The PRIORITY parameter specifies various flags - such as DMA, atomicity, etc. It is not used by Mach. */ -void * -linux_kmalloc (unsigned int size, int priority) -{ - int order, coalesced = 0; - struct pagehdr *ph; - struct blkhdr *bh, *new_bh; - - if (size < MIN_ALLOC) - size = MIN_ALLOC; - else - size = (size + CACHE_LINE - 1) & ~(CACHE_LINE - 1); - - mutex_lock (&mem_lock); - - if (size > (MEM_CHUNK_SIZE - sizeof (struct pagehdr) - - sizeof (struct blkhdr))) - { - error_t err; - int i; - - /* Find an extra slot. */ - for (i = MEM_CHUNKS; i < MEM_CHUNKS_TOTAL; i++) - if (pages_free[i].end == 0) - break; - - // TODO use a dynamically allocated memory to - // record directly allocated large memory. - assert (i < MEM_CHUNKS_TOTAL); - size = ROUND_UP (size); - err = vm_dma_buff_alloc (priv_host, mach_task_self (), size, - &pages_free[i].start, &pages_free[i].pstart); - if (!err) - pages_free[i].end = pages_free[i].start + size; - mutex_unlock (&mem_lock); - fprintf (stderr, "allocate %d bytes at (virt: %x, phys: %x), slot %d\n", - size, pages_free[i].start, pages_free[i].pstart, i); - - return err ? NULL : (void *) pages_free[i].start; - } - -again: - check_page_list (__LINE__); - - /* Walk the page list and find the first free block with size - greater than or equal to the one required. */ - for (ph = memlist; ph; ph = ph->next) - { - bh = (struct blkhdr *) (ph + 1); - while (bh < (struct blkhdr *) ((void *) ph + ph->size)) - { - if (bh->free && bh->size >= size) - { - bh->free = 0; - if (bh->size - size >= MIN_ALLOC + sizeof (struct blkhdr)) - { - /* Split the current block and create a new free block. */ - new_bh = (void *) (bh + 1) + size; - new_bh->free = 1; - new_bh->size = bh->size - size - sizeof (struct blkhdr); - bh->size = size; - } - - check_page_list (__LINE__); - - mutex_unlock (&mem_lock); - return bh + 1; - } - bh = (void *) (bh + 1) + bh->size; - } - } - - check_page_list (__LINE__); - - /* Allocation failed; coalesce free blocks and try again. */ - if (!coalesced) - { - coalesce_blocks (); - coalesced = 1; - goto again; - } - - /* Allocate more pages. */ - order = get_page_order (size - + sizeof (struct pagehdr) - + sizeof (struct blkhdr)); - ph = (struct pagehdr *) __get_free_pages (order, ~0UL); - if (!ph) - { - mutex_unlock (&mem_lock); - return NULL; - } - - ph->size = PAGE_SIZE << order; - ph->next = memlist; - memlist = ph; - bh = (struct blkhdr *) (ph + 1); - bh->free = 0; - bh->size = ph->size - sizeof (struct pagehdr) - sizeof (struct blkhdr); - if (bh->size - size >= MIN_ALLOC + sizeof (struct blkhdr)) - { - new_bh = (void *) (bh + 1) + size; - new_bh->free = 1; - new_bh->size = bh->size - size - sizeof (struct blkhdr); - bh->size = size; - } - - check_page_list (__LINE__); - - mutex_unlock (&mem_lock); - return bh + 1; -} - -/* Free memory P previously allocated by linux_kmalloc. */ -void -linux_kfree (void *p) -{ - struct blkhdr *bh; - struct pagehdr *ph; - int i; - - assert (((int) p & (sizeof (int) - 1)) == 0); - - mutex_lock (&mem_lock); - - for (i = MEM_CHUNKS; i < MEM_CHUNKS_TOTAL; i++) - { - if ((vm_address_t) p == pages_free[i].start) - { - // TODO I think the page cannot be deallocated. - vm_deallocate (mach_task_self (), (vm_address_t) p, - pages_free[i].end - pages_free[i].start); - memset (pages_free + i, 0, sizeof (pages_free[i])); - mutex_unlock (&mem_lock); - return; - } - } - - check_page_list (__LINE__); - - for (ph = memlist; ph; ph = ph->next) - if (p >= (void *) ph && p < (void *) ph + ph->size) - break; - - assert (ph); - - bh = (struct blkhdr *) p - 1; - - assert (!bh->free); - assert (bh->size >= MIN_ALLOC); - assert ((bh->size & (sizeof (int) - 1)) == 0); - - bh->free = 1; - - check_page_list (__LINE__); - - mutex_unlock (&mem_lock); -} - -/* Free any pages that are not in use. - Called by __get_free_pages when pages are running low. */ -static void -collect_kmalloc_pages () -{ - struct blkhdr *bh; - struct pagehdr *ph, **prev_ph; - - check_page_list (__LINE__); - - coalesce_blocks (); - - check_page_list (__LINE__); - - ph = memlist; - prev_ph = &memlist; - while (ph) - { - bh = (struct blkhdr *) (ph + 1); - if (bh->free && (void *) (bh + 1) + bh->size == (void *) ph + ph->size) - { - *prev_ph = ph->next; - free_pages ((unsigned long) ph, get_page_order (ph->size)); - ph = *prev_ph; - } - else - { - prev_ph = &ph->next; - ph = ph->next; - } - } - - check_page_list (__LINE__); -} - -/* Allocate ORDER + 1 number of physically contiguous pages. - PRIORITY and DMA are not used in Mach. - NOTE: mem_lock has been held. - - XXX: This needs to be dynamic. To do that we need to make - the Mach page manipulation routines interrupt safe and they - must provide machine dependant hooks. */ -unsigned long -__get_free_pages (unsigned long order, int dma) -{ - int i, pages_collected = 0; - unsigned bits, off, j, len; - - assert ((PAGE_SIZE << order) <= MEM_CHUNK_SIZE); - - /* Construct bitmap of contiguous pages. */ - bits = 0; - j = 0; - len = 0; - while (len < (PAGE_SIZE << order)) - { - bits |= 1 << j++; - len += PAGE_SIZE; - } - -again: - - /* Search each chunk for the required number of contiguous pages. */ - for (i = 0; i < MEM_CHUNKS; i++) - { - off = 0; - j = bits; - while (MEM_CHUNK_SIZE - off >= (PAGE_SIZE << order)) - { - if ((pages_free[i].bitmap & j) == j) - { - pages_free[i].bitmap &= ~j; - linux_mem_avail -= order + 1; - return pages_free[i].start + off; - } - j <<= 1; - off += PAGE_SIZE; - } - } - - /* Allocation failed; collect kmalloc and buffer pages - and try again. */ - if (!pages_collected) - { - num_page_collect++; - collect_kmalloc_pages (); - pages_collected = 1; - goto again; - } - - printf ("%s:%d: __get_free_pages: ran out of pages\n", __FILE__, __LINE__); - - return 0; -} - -/* Free ORDER + 1 number of physically - contiguous pages starting at address ADDR. */ -void -free_pages (unsigned long addr, unsigned long order) -{ - int i; - unsigned bits, len, j; - - assert ((addr & PAGE_MASK) == 0); - - for (i = 0; i < MEM_CHUNKS; i++) - if (addr >= pages_free[i].start && addr < pages_free[i].end) - break; - - assert (i < MEM_CHUNKS); - - /* Contruct bitmap of contiguous pages. */ - len = 0; - j = 0; - bits = 0; - while (len < (PAGE_SIZE << order)) - { - bits |= 1 << j++; - len += PAGE_SIZE; - } - bits <<= (addr - pages_free[i].start) >> PAGE_SHIFT; - - mutex_lock (&mem_lock); - - assert ((pages_free[i].bitmap & bits) == 0); - - pages_free[i].bitmap |= bits; - linux_mem_avail += order + 1; - mutex_unlock (&mem_lock); -} diff --git a/libddekit/memory.c b/libddekit/memory.c index 03752211..79fe0ad3 100644 --- a/libddekit/memory.c +++ b/libddekit/memory.c @@ -16,16 +16,16 @@ #include #include #include + #include "mach_U.h" +#include "libhurd-slab/slab.h" #include "util.h" #include "ddekit/memory.h" #include "ddekit/panic.h" #include "ddekit/pgtab.h" -extern void * linux_kmalloc (unsigned int size, int priority); -extern void linux_kfree (void *p); - +#define CACHE_LINE_SIZE 32 /**************** ** Page cache ** @@ -81,8 +81,7 @@ void ddekit_slab_setup_page_cache(unsigned pages) /* ddekit slab facilitates l4slabs */ struct ddekit_slab { - int size; - int contiguous; + struct hurd_slab_space space; }; /** @@ -90,10 +89,9 @@ struct ddekit_slab */ void *ddekit_slab_alloc(struct ddekit_slab * slab) { - if (slab->contiguous) - return linux_kmalloc (slab->size, 0); - else - return ddekit_simple_malloc (slab->size); + void *buffer; + error_t err = hurd_slab_alloc (&slab->space, &buffer); + return err ? NULL : buffer; } @@ -102,10 +100,7 @@ void *ddekit_slab_alloc(struct ddekit_slab * slab) */ void ddekit_slab_free(struct ddekit_slab * slab, void *objp) { - if (slab->contiguous) - linux_kfree (objp); - else - ddekit_simple_free (objp); + hurd_slab_dealloc (&slab->space, objp); } @@ -141,9 +136,22 @@ void *ddekit_slab_get_data(struct ddekit_slab * slab) */ void ddekit_slab_destroy (struct ddekit_slab * slab) { - ddekit_simple_free(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 @@ -156,10 +164,21 @@ void ddekit_slab_destroy (struct ddekit_slab * slab) struct ddekit_slab * ddekit_slab_init(unsigned size, int contiguous) { struct ddekit_slab * slab; + error_t err; - slab = (struct ddekit_slab *) ddekit_simple_malloc(sizeof(*slab)); - slab->size = size; - slab->contiguous = contiguous; + 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; } diff --git a/libddekit/pgtab.c b/libddekit/pgtab.c index 35cc630a..f39fc40a 100644 --- a/libddekit/pgtab.c +++ b/libddekit/pgtab.c @@ -82,14 +82,14 @@ ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virtual) e = get_entry_from_virt ((ddekit_addr_t) virtual); if (e) { - ddekit_addr_t phys = e->physical; + ddekit_addr_t phys = e->physical + (virtual - e->virtual); mutex_unlock (&lock); return phys; } mutex_unlock (&lock); - extern int virt_to_phys (vm_address_t addr); - return virt_to_phys ((vm_address_t) virtual); + ddekit_printf ("a virtual address %p doesn't exist.\n", virtual); + return -1; } /** @@ -106,14 +106,16 @@ ddekit_addr_t ddekit_pgtab_get_virtaddr(const ddekit_addr_t physical) e = get_entry_from_phys (physical); if (e) { - ddekit_addr_t virt = (ddekit_addr_t) e->virtual; + ddekit_addr_t virt = (ddekit_addr_t) e->virtual + + (physical - e->physical); mutex_unlock (&lock); return virt; } mutex_unlock (&lock); - extern int phys_to_virt (vm_address_t addr); - return phys_to_virt (physical); + + ddekit_printf ("a physical address %p doesn't exist.\n", physical); + return -1; } // TODO -- cgit v1.2.3 From 8be479740f0d7cdf8e78bf5c62ba934afdd9dca1 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Mon, 31 May 2010 17:19:57 +0200 Subject: change Makefile to install ddekit header files. --- libddekit/Makefile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index f0f6be87..ea64a6f5 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -32,7 +32,15 @@ LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ include/ddekit/memory.h include/ddekit/timer.h \ include/dde.h \ config.h list.h util.h -installhdrs = +installhdrs = include/ddekit/condvar.h include/ddekit/lock.h \ + include/ddekit/semaphore.h include/ddekit/debug.h \ + include/ddekit/inline.h include/ddekit/panic.h \ + include/ddekit/thread.h include/ddekit/types.h \ + include/ddekit/pgtab.h include/ddekit/printf.h \ + include/ddekit/pci.h include/ddekit/assert.h \ + include/ddekit/interrupt.h include/ddekit/resources.h \ + include/ddekit/memory.h include/ddekit/timer.h \ + include/dde.h MIGSTUBS = deviceUser.o machUser.o OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS)) -- cgit v1.2.3 From 876d456e2da0e5275ab985a36b49d4e995ccd9e0 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 5 Jun 2010 05:06:09 +0200 Subject: remove printing. --- libddekit/pgtab.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'libddekit') diff --git a/libddekit/pgtab.c b/libddekit/pgtab.c index f39fc40a..e7a94599 100644 --- a/libddekit/pgtab.c +++ b/libddekit/pgtab.c @@ -202,8 +202,6 @@ void ddekit_pgtab_set_region_with_size(void *virt, ddekit_addr_t phys, int size, regions[num_regions].type = type; num_regions++; mutex_unlock (&lock); - ddekit_printf ("******there are %d regions (%d bytes)\n", - num_regions, size); } int pgtab_init () -- cgit v1.2.3 From 13e0bf0fc4959a448fe8d1f33eb6eac01b4c4e06 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 9 Jun 2010 13:49:20 +0200 Subject: make __l4ddekit_initcall_* variables global. --- libddekit/include/ddekit/initcall.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit') diff --git a/libddekit/include/ddekit/initcall.h b/libddekit/include/ddekit/initcall.h index b503cc6a..6befa31c 100644 --- a/libddekit/include/ddekit/initcall.h +++ b/libddekit/include/ddekit/initcall.h @@ -30,7 +30,7 @@ typedef void (*l4ddekit_initcall_t)(void); #define DDEKIT_INITCALL(fn) DDEKIT_CTOR(fn, 1) #define DDEKIT_CTOR(fn, prio) \ - static l4ddekit_initcall_t \ + l4ddekit_initcall_t \ L4_STICKY(__l4ddekit_initcall_##fn) \ __l4ddekit_initcall(prio) = (void *)fn -- cgit v1.2.3 From 79110264f65e0209887dbe1b2a8609a34909c591 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 9 Jun 2010 13:51:38 +0200 Subject: fix a race condition in the interrupt handler. --- libddekit/interrupt.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'libddekit') diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index 5a545f5a..9128e4d0 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -208,6 +208,11 @@ ddekit_thread_t *ddekit_interrupt_attach(int irq, int 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); @@ -215,12 +220,7 @@ ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, 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_lock_init_unlocked (&ddekit_irq_ctrl[irq].irqlock); - ddekit_irq_ctrl[irq].cond = ddekit_condvar_init (); - ddekit_irq_ctrl[irq].thread_exit = FALSE; /* wait for intloop initialization result */ -- cgit v1.2.3 From 63dfd78334843070ddd110fc24e30f65c9b4ac6a Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Mon, 14 Jun 2010 22:54:27 +0200 Subject: fix compiling problems in libddekit and libmachdev. --- libddekit/Makefile | 12 ++---------- libmachdev/Makefile | 4 ++-- 2 files changed, 4 insertions(+), 12 deletions(-) (limited to 'libddekit') diff --git a/libddekit/Makefile b/libddekit/Makefile index ea64a6f5..a163a0c0 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -32,15 +32,7 @@ LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ include/ddekit/memory.h include/ddekit/timer.h \ include/dde.h \ config.h list.h util.h -installhdrs = include/ddekit/condvar.h include/ddekit/lock.h \ - include/ddekit/semaphore.h include/ddekit/debug.h \ - include/ddekit/inline.h include/ddekit/panic.h \ - include/ddekit/thread.h include/ddekit/types.h \ - include/ddekit/pgtab.h include/ddekit/printf.h \ - include/ddekit/pci.h include/ddekit/assert.h \ - include/ddekit/interrupt.h include/ddekit/resources.h \ - include/ddekit/memory.h include/ddekit/timer.h \ - include/dde.h +installhdrs = MIGSTUBS = deviceUser.o machUser.o OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS)) @@ -52,4 +44,4 @@ MIGCOMSFLAGS = -prefix dde_ include ../Makeconf LDFLAGS += -lpciaccess -CFLAGS += -Iinclude +CFLAGS += -I$(srcdir)/include diff --git a/libmachdev/Makefile b/libmachdev/Makefile index 7475d041..e65a453a 100644 --- a/libmachdev/Makefile +++ b/libmachdev/Makefile @@ -24,10 +24,10 @@ SRCS = deviceUser.c machUser.c net.c ds_routines.c queue.c trivfs_server.c \ LCLHDRS = dev_hdr.h device_emul.h ds_routines.h vm_param.h \ util.h queue.h io_req.h if_ether.h machdev.h linux-errno.h \ errno-base.h -installhdrs = machdev.h device_emul.h +installhdrs = HURDLIBS = ports threads trivfs OBJS = $(SRCS:.c=.o) $(MIGSTUBS) include ../Makeconf -CFLAGS += -I../libddekit/include +CFLAGS += -I$(top_srcdir)/libddekit/include -- cgit v1.2.3 From 9cd3c840876b1f3ea79ab810a5b00d9931749631 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 15 Jun 2010 16:20:24 +0200 Subject: implement get_random_bytes() with random() in libc --- libdde_linux26/contrib/drivers/char/random.c | 1691 ------------------------- libdde_linux26/lib/src/Makefile | 3 +- libdde_linux26/lib/src/drivers/char/random.c | 1709 ++++++++++++++++++++++++++ libddekit/include/ddekit/resources.h | 1 + libddekit/resources.c | 6 + 5 files changed, 1718 insertions(+), 1692 deletions(-) delete mode 100644 libdde_linux26/contrib/drivers/char/random.c create mode 100644 libdde_linux26/lib/src/drivers/char/random.c (limited to 'libddekit') diff --git a/libdde_linux26/contrib/drivers/char/random.c b/libdde_linux26/contrib/drivers/char/random.c deleted file mode 100644 index 7c13581c..00000000 --- a/libdde_linux26/contrib/drivers/char/random.c +++ /dev/null @@ -1,1691 +0,0 @@ -/* - * random.c -- A strong random number generator - * - * Copyright Matt Mackall , 2003, 2004, 2005 - * - * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All - * rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU General Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ - -/* - * (now, with legal B.S. out of the way.....) - * - * This routine gathers environmental noise from device drivers, etc., - * and returns good random numbers, suitable for cryptographic use. - * Besides the obvious cryptographic uses, these numbers are also good - * for seeding TCP sequence numbers, and other places where it is - * desirable to have numbers which are not only random, but hard to - * predict by an attacker. - * - * Theory of operation - * =================== - * - * Computers are very predictable devices. Hence it is extremely hard - * to produce truly random numbers on a computer --- as opposed to - * pseudo-random numbers, which can easily generated by using a - * algorithm. Unfortunately, it is very easy for attackers to guess - * the sequence of pseudo-random number generators, and for some - * applications this is not acceptable. So instead, we must try to - * gather "environmental noise" from the computer's environment, which - * must be hard for outside attackers to observe, and use that to - * generate random numbers. In a Unix environment, this is best done - * from inside the kernel. - * - * Sources of randomness from the environment include inter-keyboard - * timings, inter-interrupt timings from some interrupts, and other - * events which are both (a) non-deterministic and (b) hard for an - * outside observer to measure. Randomness from these sources are - * added to an "entropy pool", which is mixed using a CRC-like function. - * This is not cryptographically strong, but it is adequate assuming - * the randomness is not chosen maliciously, and it is fast enough that - * the overhead of doing it on every interrupt is very reasonable. - * As random bytes are mixed into the entropy pool, the routines keep - * an *estimate* of how many bits of randomness have been stored into - * the random number generator's internal state. - * - * When random bytes are desired, they are obtained by taking the SHA - * hash of the contents of the "entropy pool". The SHA hash avoids - * exposing the internal state of the entropy pool. It is believed to - * be computationally infeasible to derive any useful information - * about the input of SHA from its output. Even if it is possible to - * analyze SHA in some clever way, as long as the amount of data - * returned from the generator is less than the inherent entropy in - * the pool, the output data is totally unpredictable. For this - * reason, the routine decreases its internal estimate of how many - * bits of "true randomness" are contained in the entropy pool as it - * outputs random numbers. - * - * If this estimate goes to zero, the routine can still generate - * random numbers; however, an attacker may (at least in theory) be - * able to infer the future output of the generator from prior - * outputs. This requires successful cryptanalysis of SHA, which is - * not believed to be feasible, but there is a remote possibility. - * Nonetheless, these numbers should be useful for the vast majority - * of purposes. - * - * Exported interfaces ---- output - * =============================== - * - * There are three exported interfaces; the first is one designed to - * be used from within the kernel: - * - * void get_random_bytes(void *buf, int nbytes); - * - * This interface will return the requested number of random bytes, - * and place it in the requested buffer. - * - * The two other interfaces are two character devices /dev/random and - * /dev/urandom. /dev/random is suitable for use when very high - * quality randomness is desired (for example, for key generation or - * one-time pads), as it will only return a maximum of the number of - * bits of randomness (as estimated by the random number generator) - * contained in the entropy pool. - * - * The /dev/urandom device does not have this limit, and will return - * as many bytes as are requested. As more and more random bytes are - * requested without giving time for the entropy pool to recharge, - * this will result in random numbers that are merely cryptographically - * strong. For many applications, however, this is acceptable. - * - * Exported interfaces ---- input - * ============================== - * - * The current exported interfaces for gathering environmental noise - * from the devices are: - * - * void add_input_randomness(unsigned int type, unsigned int code, - * unsigned int value); - * void add_interrupt_randomness(int irq); - * - * add_input_randomness() uses the input layer interrupt timing, as well as - * the event type information from the hardware. - * - * add_interrupt_randomness() uses the inter-interrupt timing as random - * inputs to the entropy pool. Note that not all interrupts are good - * sources of randomness! For example, the timer interrupts is not a - * good choice, because the periodicity of the interrupts is too - * regular, and hence predictable to an attacker. Disk interrupts are - * a better measure, since the timing of the disk interrupts are more - * unpredictable. - * - * All of these routines try to estimate how many bits of randomness a - * particular randomness source. They do this by keeping track of the - * first and second order deltas of the event timings. - * - * Ensuring unpredictability at system startup - * ============================================ - * - * When any operating system starts up, it will go through a sequence - * of actions that are fairly predictable by an adversary, especially - * if the start-up does not involve interaction with a human operator. - * This reduces the actual number of bits of unpredictability in the - * entropy pool below the value in entropy_count. In order to - * counteract this effect, it helps to carry information in the - * entropy pool across shut-downs and start-ups. To do this, put the - * following lines an appropriate script which is run during the boot - * sequence: - * - * echo "Initializing random number generator..." - * random_seed=/var/run/random-seed - * # Carry a random seed from start-up to start-up - * # Load and then save the whole entropy pool - * if [ -f $random_seed ]; then - * cat $random_seed >/dev/urandom - * else - * touch $random_seed - * fi - * chmod 600 $random_seed - * dd if=/dev/urandom of=$random_seed count=1 bs=512 - * - * and the following lines in an appropriate script which is run as - * the system is shutdown: - * - * # Carry a random seed from shut-down to start-up - * # Save the whole entropy pool - * echo "Saving random seed..." - * random_seed=/var/run/random-seed - * touch $random_seed - * chmod 600 $random_seed - * dd if=/dev/urandom of=$random_seed count=1 bs=512 - * - * For example, on most modern systems using the System V init - * scripts, such code fragments would be found in - * /etc/rc.d/init.d/random. On older Linux systems, the correct script - * location might be in /etc/rcb.d/rc.local or /etc/rc.d/rc.0. - * - * Effectively, these commands cause the contents of the entropy pool - * to be saved at shut-down time and reloaded into the entropy pool at - * start-up. (The 'dd' in the addition to the bootup script is to - * make sure that /etc/random-seed is different for every start-up, - * even if the system crashes without executing rc.0.) Even with - * complete knowledge of the start-up activities, predicting the state - * of the entropy pool requires knowledge of the previous history of - * the system. - * - * Configuring the /dev/random driver under Linux - * ============================================== - * - * The /dev/random driver under Linux uses minor numbers 8 and 9 of - * the /dev/mem major number (#1). So if your system does not have - * /dev/random and /dev/urandom created already, they can be created - * by using the commands: - * - * mknod /dev/random c 1 8 - * mknod /dev/urandom c 1 9 - * - * Acknowledgements: - * ================= - * - * Ideas for constructing this random number generator were derived - * from Pretty Good Privacy's random number generator, and from private - * discussions with Phil Karn. Colin Plumb provided a faster random - * number generator, which speed up the mixing function of the entropy - * pool, taken from PGPfone. Dale Worley has also contributed many - * useful ideas and suggestions to improve this driver. - * - * Any flaws in the design are solely my responsibility, and should - * not be attributed to the Phil, Colin, or any of authors of PGP. - * - * Further background information on this topic may be obtained from - * RFC 1750, "Randomness Recommendations for Security", by Donald - * Eastlake, Steve Crocker, and Jeff Schiller. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* - * Configuration information - */ -#define INPUT_POOL_WORDS 128 -#define OUTPUT_POOL_WORDS 32 -#define SEC_XFER_SIZE 512 - -/* - * The minimum number of bits of entropy before we wake up a read on - * /dev/random. Should be enough to do a significant reseed. - */ -static int random_read_wakeup_thresh = 64; - -/* - * If the entropy count falls under this number of bits, then we - * should wake up processes which are selecting or polling on write - * access to /dev/random. - */ -static int random_write_wakeup_thresh = 128; - -/* - * When the input pool goes over trickle_thresh, start dropping most - * samples to avoid wasting CPU time and reduce lock contention. - */ - -static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28; - -static DEFINE_PER_CPU(int, trickle_count); - -/* - * A pool of size .poolwords is stirred with a primitive polynomial - * of degree .poolwords over GF(2). The taps for various sizes are - * defined below. They are chosen to be evenly spaced (minimum RMS - * distance from evenly spaced; the numbers in the comments are a - * scaled squared error sum) except for the last tap, which is 1 to - * get the twisting happening as fast as possible. - */ -static struct poolinfo { - int poolwords; - int tap1, tap2, tap3, tap4, tap5; -} poolinfo_table[] = { - /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */ - { 128, 103, 76, 51, 25, 1 }, - /* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */ - { 32, 26, 20, 14, 7, 1 }, -#if 0 - /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */ - { 2048, 1638, 1231, 819, 411, 1 }, - - /* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */ - { 1024, 817, 615, 412, 204, 1 }, - - /* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */ - { 1024, 819, 616, 410, 207, 2 }, - - /* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */ - { 512, 411, 308, 208, 104, 1 }, - - /* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */ - { 512, 409, 307, 206, 102, 2 }, - /* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */ - { 512, 409, 309, 205, 103, 2 }, - - /* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */ - { 256, 205, 155, 101, 52, 1 }, - - /* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */ - { 128, 103, 78, 51, 27, 2 }, - - /* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */ - { 64, 52, 39, 26, 14, 1 }, -#endif -}; - -#define POOLBITS poolwords*32 -#define POOLBYTES poolwords*4 - -/* - * For the purposes of better mixing, we use the CRC-32 polynomial as - * well to make a twisted Generalized Feedback Shift Reigster - * - * (See M. Matsumoto & Y. Kurita, 1992. Twisted GFSR generators. ACM - * Transactions on Modeling and Computer Simulation 2(3):179-194. - * Also see M. Matsumoto & Y. Kurita, 1994. Twisted GFSR generators - * II. ACM Transactions on Mdeling and Computer Simulation 4:254-266) - * - * Thanks to Colin Plumb for suggesting this. - * - * We have not analyzed the resultant polynomial to prove it primitive; - * in fact it almost certainly isn't. Nonetheless, the irreducible factors - * of a random large-degree polynomial over GF(2) are more than large enough - * that periodicity is not a concern. - * - * The input hash is much less sensitive than the output hash. All - * that we want of it is that it be a good non-cryptographic hash; - * i.e. it not produce collisions when fed "random" data of the sort - * we expect to see. As long as the pool state differs for different - * inputs, we have preserved the input entropy and done a good job. - * The fact that an intelligent attacker can construct inputs that - * will produce controlled alterations to the pool's state is not - * important because we don't consider such inputs to contribute any - * randomness. The only property we need with respect to them is that - * the attacker can't increase his/her knowledge of the pool's state. - * Since all additions are reversible (knowing the final state and the - * input, you can reconstruct the initial state), if an attacker has - * any uncertainty about the initial state, he/she can only shuffle - * that uncertainty about, but never cause any collisions (which would - * decrease the uncertainty). - * - * The chosen system lets the state of the pool be (essentially) the input - * modulo the generator polymnomial. Now, for random primitive polynomials, - * this is a universal class of hash functions, meaning that the chance - * of a collision is limited by the attacker's knowledge of the generator - * polynomail, so if it is chosen at random, an attacker can never force - * a collision. Here, we use a fixed polynomial, but we *can* assume that - * ###--> it is unknown to the processes generating the input entropy. <-### - * Because of this important property, this is a good, collision-resistant - * hash; hash collisions will occur no more often than chance. - */ - -/* - * Static global variables - */ -static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); -static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); -static struct fasync_struct *fasync; - -#if 0 -static int debug; -module_param(debug, bool, 0644); -#define DEBUG_ENT(fmt, arg...) do { \ - if (debug) \ - printk(KERN_DEBUG "random %04d %04d %04d: " \ - fmt,\ - input_pool.entropy_count,\ - blocking_pool.entropy_count,\ - nonblocking_pool.entropy_count,\ - ## arg); } while (0) -#else -#define DEBUG_ENT(fmt, arg...) do {} while (0) -#endif - -/********************************************************************** - * - * OS independent entropy store. Here are the functions which handle - * storing entropy in an entropy pool. - * - **********************************************************************/ - -struct entropy_store; -struct entropy_store { - /* read-only data: */ - struct poolinfo *poolinfo; - __u32 *pool; - const char *name; - int limit; - struct entropy_store *pull; - - /* read-write data: */ - spinlock_t lock; - unsigned add_ptr; - int entropy_count; - int input_rotate; -}; - -static __u32 input_pool_data[INPUT_POOL_WORDS]; -static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; -static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS]; - -static struct entropy_store input_pool = { - .poolinfo = &poolinfo_table[0], - .name = "input", - .limit = 1, - .lock = __SPIN_LOCK_UNLOCKED(&input_pool.lock), - .pool = input_pool_data -}; - -static struct entropy_store blocking_pool = { - .poolinfo = &poolinfo_table[1], - .name = "blocking", - .limit = 1, - .pull = &input_pool, - .lock = __SPIN_LOCK_UNLOCKED(&blocking_pool.lock), - .pool = blocking_pool_data -}; - -static struct entropy_store nonblocking_pool = { - .poolinfo = &poolinfo_table[1], - .name = "nonblocking", - .pull = &input_pool, - .lock = __SPIN_LOCK_UNLOCKED(&nonblocking_pool.lock), - .pool = nonblocking_pool_data -}; - -/* - * This function adds bytes into the entropy "pool". It does not - * update the entropy estimate. The caller should call - * credit_entropy_bits if this is appropriate. - * - * The pool is stirred with a primitive polynomial of the appropriate - * degree, and then twisted. We twist by three bits at a time because - * it's cheap to do so and helps slightly in the expected case where - * the entropy is concentrated in the low-order bits. - */ -static void mix_pool_bytes_extract(struct entropy_store *r, const void *in, - int nbytes, __u8 out[64]) -{ - static __u32 const twist_table[8] = { - 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, - 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; - unsigned long i, j, tap1, tap2, tap3, tap4, tap5; - int input_rotate; - int wordmask = r->poolinfo->poolwords - 1; - const char *bytes = in; - __u32 w; - unsigned long flags; - - /* Taps are constant, so we can load them without holding r->lock. */ - tap1 = r->poolinfo->tap1; - tap2 = r->poolinfo->tap2; - tap3 = r->poolinfo->tap3; - tap4 = r->poolinfo->tap4; - tap5 = r->poolinfo->tap5; - - spin_lock_irqsave(&r->lock, flags); - input_rotate = r->input_rotate; - i = r->add_ptr; - - /* mix one byte at a time to simplify size handling and churn faster */ - while (nbytes--) { - w = rol32(*bytes++, input_rotate & 31); - i = (i - 1) & wordmask; - - /* XOR in the various taps */ - w ^= r->pool[i]; - w ^= r->pool[(i + tap1) & wordmask]; - w ^= r->pool[(i + tap2) & wordmask]; - w ^= r->pool[(i + tap3) & wordmask]; - w ^= r->pool[(i + tap4) & wordmask]; - w ^= r->pool[(i + tap5) & wordmask]; - - /* Mix the result back in with a twist */ - r->pool[i] = (w >> 3) ^ twist_table[w & 7]; - - /* - * Normally, we add 7 bits of rotation to the pool. - * At the beginning of the pool, add an extra 7 bits - * rotation, so that successive passes spread the - * input bits across the pool evenly. - */ - input_rotate += i ? 7 : 14; - } - - r->input_rotate = input_rotate; - r->add_ptr = i; - - if (out) - for (j = 0; j < 16; j++) - ((__u32 *)out)[j] = r->pool[(i - j) & wordmask]; - - spin_unlock_irqrestore(&r->lock, flags); -} - -static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes) -{ - mix_pool_bytes_extract(r, in, bytes, NULL); -} - -/* - * Credit (or debit) the entropy store with n bits of entropy - */ -static void credit_entropy_bits(struct entropy_store *r, int nbits) -{ - unsigned long flags; - int entropy_count; - - if (!nbits) - return; - - spin_lock_irqsave(&r->lock, flags); - - DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); - entropy_count = r->entropy_count; - entropy_count += nbits; - if (entropy_count < 0) { - DEBUG_ENT("negative entropy/overflow\n"); - entropy_count = 0; - } else if (entropy_count > r->poolinfo->POOLBITS) - entropy_count = r->poolinfo->POOLBITS; - r->entropy_count = entropy_count; - - /* should we wake readers? */ - if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) { - wake_up_interruptible(&random_read_wait); - kill_fasync(&fasync, SIGIO, POLL_IN); - } - spin_unlock_irqrestore(&r->lock, flags); -} - -/********************************************************************* - * - * Entropy input management - * - *********************************************************************/ - -/* There is one of these per entropy source */ -struct timer_rand_state { - cycles_t last_time; - long last_delta, last_delta2; - unsigned dont_count_entropy:1; -}; - -#ifndef CONFIG_SPARSE_IRQ - -static struct timer_rand_state *irq_timer_state[NR_IRQS]; - -static struct timer_rand_state *get_timer_rand_state(unsigned int irq) -{ - return irq_timer_state[irq]; -} - -static void set_timer_rand_state(unsigned int irq, - struct timer_rand_state *state) -{ - irq_timer_state[irq] = state; -} - -#else - -static struct timer_rand_state *get_timer_rand_state(unsigned int irq) -{ - struct irq_desc *desc; - - desc = irq_to_desc(irq); - - return desc->timer_rand_state; -} - -static void set_timer_rand_state(unsigned int irq, - struct timer_rand_state *state) -{ - struct irq_desc *desc; - - desc = irq_to_desc(irq); - - desc->timer_rand_state = state; -} -#endif - -static struct timer_rand_state input_timer_state; - -/* - * This function adds entropy to the entropy "pool" by using timing - * delays. It uses the timer_rand_state structure to make an estimate - * of how many bits of entropy this call has added to the pool. - * - * The number "num" is also added to the pool - it should somehow describe - * the type of event which just happened. This is currently 0-255 for - * keyboard scan codes, and 256 upwards for interrupts. - * - */ -static void add_timer_randomness(struct timer_rand_state *state, unsigned num) -{ - struct { - cycles_t cycles; - long jiffies; - unsigned num; - } sample; - long delta, delta2, delta3; - - preempt_disable(); - /* if over the trickle threshold, use only 1 in 4096 samples */ - if (input_pool.entropy_count > trickle_thresh && - (__get_cpu_var(trickle_count)++ & 0xfff)) - goto out; - - sample.jiffies = jiffies; - sample.cycles = get_cycles(); - sample.num = num; - mix_pool_bytes(&input_pool, &sample, sizeof(sample)); - - /* - * Calculate number of bits of randomness we probably added. - * We take into account the first, second and third-order deltas - * in order to make our estimate. - */ - - if (!state->dont_count_entropy) { - delta = sample.jiffies - state->last_time; - state->last_time = sample.jiffies; - - delta2 = delta - state->last_delta; - state->last_delta = delta; - - delta3 = delta2 - state->last_delta2; - state->last_delta2 = delta2; - - if (delta < 0) - delta = -delta; - if (delta2 < 0) - delta2 = -delta2; - if (delta3 < 0) - delta3 = -delta3; - if (delta > delta2) - delta = delta2; - if (delta > delta3) - delta = delta3; - - /* - * delta is now minimum absolute delta. - * Round down by 1 bit on general principles, - * and limit entropy entimate to 12 bits. - */ - credit_entropy_bits(&input_pool, - min_t(int, fls(delta>>1), 11)); - } -out: - preempt_enable(); -} - -void add_input_randomness(unsigned int type, unsigned int code, - unsigned int value) -{ - static unsigned char last_value; - - /* ignore autorepeat and the like */ - if (value == last_value) - return; - - DEBUG_ENT("input event\n"); - last_value = value; - add_timer_randomness(&input_timer_state, - (type << 4) ^ code ^ (code >> 4) ^ value); -} -EXPORT_SYMBOL_GPL(add_input_randomness); - -void add_interrupt_randomness(int irq) -{ - struct timer_rand_state *state; - - state = get_timer_rand_state(irq); - - if (state == NULL) - return; - - DEBUG_ENT("irq event %d\n", irq); - add_timer_randomness(state, 0x100 + irq); -} - -#ifdef CONFIG_BLOCK -void add_disk_randomness(struct gendisk *disk) -{ - if (!disk || !disk->random) - return; - /* first major is 1, so we get >= 0x200 here */ - DEBUG_ENT("disk event %d:%d\n", - MAJOR(disk_devt(disk)), MINOR(disk_devt(disk))); - - add_timer_randomness(disk->random, 0x100 + disk_devt(disk)); -} -#endif - -#define EXTRACT_SIZE 10 - -/********************************************************************* - * - * Entropy extraction routines - * - *********************************************************************/ - -static ssize_t extract_entropy(struct entropy_store *r, void *buf, - size_t nbytes, int min, int rsvd); - -/* - * This utility inline function is responsible for transfering entropy - * from the primary pool to the secondary extraction pool. We make - * sure we pull enough for a 'catastrophic reseed'. - */ -static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) -{ - __u32 tmp[OUTPUT_POOL_WORDS]; - - if (r->pull && r->entropy_count < nbytes * 8 && - r->entropy_count < r->poolinfo->POOLBITS) { - /* If we're limited, always leave two wakeup worth's BITS */ - int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; - int bytes = nbytes; - - /* pull at least as many as BYTES as wakeup BITS */ - bytes = max_t(int, bytes, random_read_wakeup_thresh / 8); - /* but never more than the buffer size */ - bytes = min_t(int, bytes, sizeof(tmp)); - - DEBUG_ENT("going to reseed %s with %d bits " - "(%d of %d requested)\n", - r->name, bytes * 8, nbytes * 8, r->entropy_count); - - bytes = extract_entropy(r->pull, tmp, bytes, - random_read_wakeup_thresh / 8, rsvd); - mix_pool_bytes(r, tmp, bytes); - credit_entropy_bits(r, bytes*8); - } -} - -/* - * These functions extracts randomness from the "entropy pool", and - * returns it in a buffer. - * - * The min parameter specifies the minimum amount we can pull before - * failing to avoid races that defeat catastrophic reseeding while the - * reserved parameter indicates how much entropy we must leave in the - * pool after each pull to avoid starving other readers. - * - * Note: extract_entropy() assumes that .poolwords is a multiple of 16 words. - */ - -static size_t account(struct entropy_store *r, size_t nbytes, int min, - int reserved) -{ - unsigned long flags; - - /* Hold lock while accounting */ - spin_lock_irqsave(&r->lock, flags); - - BUG_ON(r->entropy_count > r->poolinfo->POOLBITS); - DEBUG_ENT("trying to extract %d bits from %s\n", - nbytes * 8, r->name); - - /* Can we pull enough? */ - if (r->entropy_count / 8 < min + reserved) { - nbytes = 0; - } else { - /* If limited, never pull more than available */ - if (r->limit && nbytes + reserved >= r->entropy_count / 8) - nbytes = r->entropy_count/8 - reserved; - - if (r->entropy_count / 8 >= nbytes + reserved) - r->entropy_count -= nbytes*8; - else - r->entropy_count = reserved; - - if (r->entropy_count < random_write_wakeup_thresh) { - wake_up_interruptible(&random_write_wait); - kill_fasync(&fasync, SIGIO, POLL_OUT); - } - } - - DEBUG_ENT("debiting %d entropy credits from %s%s\n", - nbytes * 8, r->name, r->limit ? "" : " (unlimited)"); - - spin_unlock_irqrestore(&r->lock, flags); - - return nbytes; -} - -static void extract_buf(struct entropy_store *r, __u8 *out) -{ - int i; - __u32 hash[5], workspace[SHA_WORKSPACE_WORDS]; - __u8 extract[64]; - - /* Generate a hash across the pool, 16 words (512 bits) at a time */ - sha_init(hash); - for (i = 0; i < r->poolinfo->poolwords; i += 16) - sha_transform(hash, (__u8 *)(r->pool + i), workspace); - - /* - * We mix the hash back into the pool to prevent backtracking - * attacks (where the attacker knows the state of the pool - * plus the current outputs, and attempts to find previous - * ouputs), unless the hash function can be inverted. By - * mixing at least a SHA1 worth of hash data back, we make - * brute-forcing the feedback as hard as brute-forcing the - * hash. - */ - mix_pool_bytes_extract(r, hash, sizeof(hash), extract); - - /* - * To avoid duplicates, we atomically extract a portion of the - * pool while mixing, and hash one final time. - */ - sha_transform(hash, extract, workspace); - memset(extract, 0, sizeof(extract)); - memset(workspace, 0, sizeof(workspace)); - - /* - * In case the hash function has some recognizable output - * pattern, we fold it in half. Thus, we always feed back - * twice as much data as we output. - */ - hash[0] ^= hash[3]; - hash[1] ^= hash[4]; - hash[2] ^= rol32(hash[2], 16); - memcpy(out, hash, EXTRACT_SIZE); - memset(hash, 0, sizeof(hash)); -} - -static ssize_t extract_entropy(struct entropy_store *r, void *buf, - size_t nbytes, int min, int reserved) -{ - ssize_t ret = 0, i; - __u8 tmp[EXTRACT_SIZE]; - - xfer_secondary_pool(r, nbytes); - nbytes = account(r, nbytes, min, reserved); - - while (nbytes) { - extract_buf(r, tmp); - i = min_t(int, nbytes, EXTRACT_SIZE); - memcpy(buf, tmp, i); - nbytes -= i; - buf += i; - ret += i; - } - - /* Wipe data just returned from memory */ - memset(tmp, 0, sizeof(tmp)); - - return ret; -} - -static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, - size_t nbytes) -{ - ssize_t ret = 0, i; - __u8 tmp[EXTRACT_SIZE]; - - xfer_secondary_pool(r, nbytes); - nbytes = account(r, nbytes, 0, 0); - - while (nbytes) { - if (need_resched()) { - if (signal_pending(current)) { - if (ret == 0) - ret = -ERESTARTSYS; - break; - } - schedule(); - } - - extract_buf(r, tmp); - i = min_t(int, nbytes, EXTRACT_SIZE); - if (copy_to_user(buf, tmp, i)) { - ret = -EFAULT; - break; - } - - nbytes -= i; - buf += i; - ret += i; - } - - /* Wipe data just returned from memory */ - memset(tmp, 0, sizeof(tmp)); - - return ret; -} - -/* - * This function is the exported kernel interface. It returns some - * number of good random numbers, suitable for seeding TCP sequence - * numbers, etc. - */ -void get_random_bytes(void *buf, int nbytes) -{ - extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0); -} -EXPORT_SYMBOL(get_random_bytes); - -/* - * init_std_data - initialize pool with system data - * - * @r: pool to initialize - * - * This function clears the pool's entropy count and mixes some system - * data into the pool to prepare it for use. The pool is not cleared - * as that can only decrease the entropy in the pool. - */ -static void init_std_data(struct entropy_store *r) -{ - ktime_t now; - unsigned long flags; - - spin_lock_irqsave(&r->lock, flags); - r->entropy_count = 0; - spin_unlock_irqrestore(&r->lock, flags); - - now = ktime_get_real(); - mix_pool_bytes(r, &now, sizeof(now)); - mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); -} - -static int rand_initialize(void) -{ - init_std_data(&input_pool); - init_std_data(&blocking_pool); - init_std_data(&nonblocking_pool); - return 0; -} -module_init(rand_initialize); - -void rand_initialize_irq(int irq) -{ - struct timer_rand_state *state; - - state = get_timer_rand_state(irq); - - if (state) - return; - - /* - * If kzalloc returns null, we just won't use that entropy - * source. - */ - state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) - set_timer_rand_state(irq, state); -} - -#ifdef CONFIG_BLOCK -void rand_initialize_disk(struct gendisk *disk) -{ - struct timer_rand_state *state; - - /* - * If kzalloc returns null, we just won't use that entropy - * source. - */ - state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) - disk->random = state; -} -#endif - -static ssize_t -random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) -{ - ssize_t n, retval = 0, count = 0; - - if (nbytes == 0) - return 0; - - while (nbytes > 0) { - n = nbytes; - if (n > SEC_XFER_SIZE) - n = SEC_XFER_SIZE; - - DEBUG_ENT("reading %d bits\n", n*8); - - n = extract_entropy_user(&blocking_pool, buf, n); - - DEBUG_ENT("read got %d bits (%d still needed)\n", - n*8, (nbytes-n)*8); - - if (n == 0) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - - DEBUG_ENT("sleeping?\n"); - - wait_event_interruptible(random_read_wait, - input_pool.entropy_count >= - random_read_wakeup_thresh); - - DEBUG_ENT("awake\n"); - - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - - continue; - } - - if (n < 0) { - retval = n; - break; - } - count += n; - buf += n; - nbytes -= n; - break; /* This break makes the device work */ - /* like a named pipe */ - } - - /* - * If we gave the user some bytes, update the access time. - */ - if (count) - file_accessed(file); - - return (count ? count : retval); -} - -static ssize_t -urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) -{ - return extract_entropy_user(&nonblocking_pool, buf, nbytes); -} - -static unsigned int -random_poll(struct file *file, poll_table * wait) -{ - unsigned int mask; - - poll_wait(file, &random_read_wait, wait); - poll_wait(file, &random_write_wait, wait); - mask = 0; - if (input_pool.entropy_count >= random_read_wakeup_thresh) - mask |= POLLIN | POLLRDNORM; - if (input_pool.entropy_count < random_write_wakeup_thresh) - mask |= POLLOUT | POLLWRNORM; - return mask; -} - -static int -write_pool(struct entropy_store *r, const char __user *buffer, size_t count) -{ - size_t bytes; - __u32 buf[16]; - const char __user *p = buffer; - - while (count > 0) { - bytes = min(count, sizeof(buf)); - if (copy_from_user(&buf, p, bytes)) - return -EFAULT; - - count -= bytes; - p += bytes; - - mix_pool_bytes(r, buf, bytes); - cond_resched(); - } - - return 0; -} - -static ssize_t random_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) -{ - size_t ret; - struct inode *inode = file->f_path.dentry->d_inode; - - ret = write_pool(&blocking_pool, buffer, count); - if (ret) - return ret; - ret = write_pool(&nonblocking_pool, buffer, count); - if (ret) - return ret; - - inode->i_mtime = current_fs_time(inode->i_sb); - mark_inode_dirty(inode); - return (ssize_t)count; -} - -static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) -{ - int size, ent_count; - int __user *p = (int __user *)arg; - int retval; - - switch (cmd) { - case RNDGETENTCNT: - /* inherently racy, no point locking */ - if (put_user(input_pool.entropy_count, p)) - return -EFAULT; - return 0; - case RNDADDTOENTCNT: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(ent_count, p)) - return -EFAULT; - credit_entropy_bits(&input_pool, ent_count); - return 0; - case RNDADDENTROPY: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(ent_count, p++)) - return -EFAULT; - if (ent_count < 0) - return -EINVAL; - if (get_user(size, p++)) - return -EFAULT; - retval = write_pool(&input_pool, (const char __user *)p, - size); - if (retval < 0) - return retval; - credit_entropy_bits(&input_pool, ent_count); - return 0; - case RNDZAPENTCNT: - case RNDCLEARPOOL: - /* Clear the entropy pool counters. */ - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - rand_initialize(); - return 0; - default: - return -EINVAL; - } -} - -static int random_fasync(int fd, struct file *filp, int on) -{ - return fasync_helper(fd, filp, on, &fasync); -} - -const struct file_operations random_fops = { - .read = random_read, - .write = random_write, - .poll = random_poll, - .unlocked_ioctl = random_ioctl, - .fasync = random_fasync, -}; - -const struct file_operations urandom_fops = { - .read = urandom_read, - .write = random_write, - .unlocked_ioctl = random_ioctl, - .fasync = random_fasync, -}; - -/*************************************************************** - * Random UUID interface - * - * Used here for a Boot ID, but can be useful for other kernel - * drivers. - ***************************************************************/ - -/* - * Generate random UUID - */ -void generate_random_uuid(unsigned char uuid_out[16]) -{ - get_random_bytes(uuid_out, 16); - /* Set UUID version to 4 --- truely random generation */ - uuid_out[6] = (uuid_out[6] & 0x0F) | 0x40; - /* Set the UUID variant to DCE */ - uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80; -} -EXPORT_SYMBOL(generate_random_uuid); - -/******************************************************************** - * - * Sysctl interface - * - ********************************************************************/ - -#ifdef CONFIG_SYSCTL - -#include - -static int min_read_thresh = 8, min_write_thresh; -static int max_read_thresh = INPUT_POOL_WORDS * 32; -static int max_write_thresh = INPUT_POOL_WORDS * 32; -static char sysctl_bootid[16]; - -/* - * These functions is used to return both the bootid UUID, and random - * UUID. The difference is in whether table->data is NULL; if it is, - * then a new UUID is generated and returned to the user. - * - * If the user accesses this via the proc interface, it will be returned - * as an ASCII string in the standard UUID format. If accesses via the - * sysctl system call, it is returned as 16 bytes of binary data. - */ -static int proc_do_uuid(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - ctl_table fake_table; - unsigned char buf[64], tmp_uuid[16], *uuid; - - uuid = table->data; - if (!uuid) { - uuid = tmp_uuid; - uuid[8] = 0; - } - if (uuid[8] == 0) - generate_random_uuid(uuid); - - sprintf(buf, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" - "%02x%02x%02x%02x%02x%02x", - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], uuid[6], uuid[7], - uuid[8], uuid[9], uuid[10], uuid[11], - uuid[12], uuid[13], uuid[14], uuid[15]); - fake_table.data = buf; - fake_table.maxlen = sizeof(buf); - - return proc_dostring(&fake_table, write, filp, buffer, lenp, ppos); -} - -static int uuid_strategy(ctl_table *table, - void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen) -{ - unsigned char tmp_uuid[16], *uuid; - unsigned int len; - - if (!oldval || !oldlenp) - return 1; - - uuid = table->data; - if (!uuid) { - uuid = tmp_uuid; - uuid[8] = 0; - } - if (uuid[8] == 0) - generate_random_uuid(uuid); - - if (get_user(len, oldlenp)) - return -EFAULT; - if (len) { - if (len > 16) - len = 16; - if (copy_to_user(oldval, uuid, len) || - put_user(len, oldlenp)) - return -EFAULT; - } - return 1; -} - -static int sysctl_poolsize = INPUT_POOL_WORDS * 32; -ctl_table random_table[] = { - { - .ctl_name = RANDOM_POOLSIZE, - .procname = "poolsize", - .data = &sysctl_poolsize, - .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = &proc_dointvec, - }, - { - .ctl_name = RANDOM_ENTROPY_COUNT, - .procname = "entropy_avail", - .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = &proc_dointvec, - .data = &input_pool.entropy_count, - }, - { - .ctl_name = RANDOM_READ_THRESH, - .procname = "read_wakeup_threshold", - .data = &random_read_wakeup_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, - .extra1 = &min_read_thresh, - .extra2 = &max_read_thresh, - }, - { - .ctl_name = RANDOM_WRITE_THRESH, - .procname = "write_wakeup_threshold", - .data = &random_write_wakeup_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, - .extra1 = &min_write_thresh, - .extra2 = &max_write_thresh, - }, - { - .ctl_name = RANDOM_BOOT_ID, - .procname = "boot_id", - .data = &sysctl_bootid, - .maxlen = 16, - .mode = 0444, - .proc_handler = &proc_do_uuid, - .strategy = &uuid_strategy, - }, - { - .ctl_name = RANDOM_UUID, - .procname = "uuid", - .maxlen = 16, - .mode = 0444, - .proc_handler = &proc_do_uuid, - .strategy = &uuid_strategy, - }, - { .ctl_name = 0 } -}; -#endif /* CONFIG_SYSCTL */ - -/******************************************************************** - * - * Random funtions for networking - * - ********************************************************************/ - -/* - * TCP initial sequence number picking. This uses the random number - * generator to pick an initial secret value. This value is hashed - * along with the TCP endpoint information to provide a unique - * starting point for each pair of TCP endpoints. This defeats - * attacks which rely on guessing the initial TCP sequence number. - * This algorithm was suggested by Steve Bellovin. - * - * Using a very strong hash was taking an appreciable amount of the total - * TCP connection establishment time, so this is a weaker hash, - * compensated for by changing the secret periodically. - */ - -/* F, G and H are basic MD4 functions: selection, majority, parity */ -#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) - -/* - * The generic round function. The application is so specific that - * we don't bother protecting all the arguments with parens, as is generally - * good macro practice, in favor of extra legibility. - * Rotation is separate from addition to prevent recomputation - */ -#define ROUND(f, a, b, c, d, x, s) \ - (a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s))) -#define K1 0 -#define K2 013240474631UL -#define K3 015666365641UL - -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - -static __u32 twothirdsMD4Transform(__u32 const buf[4], __u32 const in[12]) -{ - __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; - - /* Round 1 */ - ROUND(F, a, b, c, d, in[ 0] + K1, 3); - ROUND(F, d, a, b, c, in[ 1] + K1, 7); - ROUND(F, c, d, a, b, in[ 2] + K1, 11); - ROUND(F, b, c, d, a, in[ 3] + K1, 19); - ROUND(F, a, b, c, d, in[ 4] + K1, 3); - ROUND(F, d, a, b, c, in[ 5] + K1, 7); - ROUND(F, c, d, a, b, in[ 6] + K1, 11); - ROUND(F, b, c, d, a, in[ 7] + K1, 19); - ROUND(F, a, b, c, d, in[ 8] + K1, 3); - ROUND(F, d, a, b, c, in[ 9] + K1, 7); - ROUND(F, c, d, a, b, in[10] + K1, 11); - ROUND(F, b, c, d, a, in[11] + K1, 19); - - /* Round 2 */ - ROUND(G, a, b, c, d, in[ 1] + K2, 3); - ROUND(G, d, a, b, c, in[ 3] + K2, 5); - ROUND(G, c, d, a, b, in[ 5] + K2, 9); - ROUND(G, b, c, d, a, in[ 7] + K2, 13); - ROUND(G, a, b, c, d, in[ 9] + K2, 3); - ROUND(G, d, a, b, c, in[11] + K2, 5); - ROUND(G, c, d, a, b, in[ 0] + K2, 9); - ROUND(G, b, c, d, a, in[ 2] + K2, 13); - ROUND(G, a, b, c, d, in[ 4] + K2, 3); - ROUND(G, d, a, b, c, in[ 6] + K2, 5); - ROUND(G, c, d, a, b, in[ 8] + K2, 9); - ROUND(G, b, c, d, a, in[10] + K2, 13); - - /* Round 3 */ - ROUND(H, a, b, c, d, in[ 3] + K3, 3); - ROUND(H, d, a, b, c, in[ 7] + K3, 9); - ROUND(H, c, d, a, b, in[11] + K3, 11); - ROUND(H, b, c, d, a, in[ 2] + K3, 15); - ROUND(H, a, b, c, d, in[ 6] + K3, 3); - ROUND(H, d, a, b, c, in[10] + K3, 9); - ROUND(H, c, d, a, b, in[ 1] + K3, 11); - ROUND(H, b, c, d, a, in[ 5] + K3, 15); - ROUND(H, a, b, c, d, in[ 9] + K3, 3); - ROUND(H, d, a, b, c, in[ 0] + K3, 9); - ROUND(H, c, d, a, b, in[ 4] + K3, 11); - ROUND(H, b, c, d, a, in[ 8] + K3, 15); - - return buf[1] + b; /* "most hashed" word */ - /* Alternative: return sum of all words? */ -} -#endif - -#undef ROUND -#undef F -#undef G -#undef H -#undef K1 -#undef K2 -#undef K3 - -/* This should not be decreased so low that ISNs wrap too fast. */ -#define REKEY_INTERVAL (300 * HZ) -/* - * Bit layout of the tcp sequence numbers (before adding current time): - * bit 24-31: increased after every key exchange - * bit 0-23: hash(source,dest) - * - * The implementation is similar to the algorithm described - * in the Appendix of RFC 1185, except that - * - it uses a 1 MHz clock instead of a 250 kHz clock - * - it performs a rekey every 5 minutes, which is equivalent - * to a (source,dest) tulple dependent forward jump of the - * clock by 0..2^(HASH_BITS+1) - * - * Thus the average ISN wraparound time is 68 minutes instead of - * 4.55 hours. - * - * SMP cleanup and lock avoidance with poor man's RCU. - * Manfred Spraul - * - */ -#define COUNT_BITS 8 -#define COUNT_MASK ((1 << COUNT_BITS) - 1) -#define HASH_BITS 24 -#define HASH_MASK ((1 << HASH_BITS) - 1) - -static struct keydata { - __u32 count; /* already shifted to the final position */ - __u32 secret[12]; -} ____cacheline_aligned ip_keydata[2]; - -static unsigned int ip_cnt; - -static void rekey_seq_generator(struct work_struct *work); - -static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator); - -/* - * Lock avoidance: - * The ISN generation runs lockless - it's just a hash over random data. - * State changes happen every 5 minutes when the random key is replaced. - * Synchronization is performed by having two copies of the hash function - * state and rekey_seq_generator always updates the inactive copy. - * The copy is then activated by updating ip_cnt. - * The implementation breaks down if someone blocks the thread - * that processes SYN requests for more than 5 minutes. Should never - * happen, and even if that happens only a not perfectly compliant - * ISN is generated, nothing fatal. - */ -static void rekey_seq_generator(struct work_struct *work) -{ - struct keydata *keyptr = &ip_keydata[1 ^ (ip_cnt & 1)]; - - get_random_bytes(keyptr->secret, sizeof(keyptr->secret)); - keyptr->count = (ip_cnt & COUNT_MASK) << HASH_BITS; - smp_wmb(); - ip_cnt++; - schedule_delayed_work(&rekey_work, REKEY_INTERVAL); -} - -static inline struct keydata *get_keyptr(void) -{ - struct keydata *keyptr = &ip_keydata[ip_cnt & 1]; - - smp_rmb(); - - return keyptr; -} - -static __init int seqgen_init(void) -{ - rekey_seq_generator(NULL); - return 0; -} -late_initcall(seqgen_init); - -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, - __be16 sport, __be16 dport) -{ - __u32 seq; - __u32 hash[12]; - struct keydata *keyptr = get_keyptr(); - - /* The procedure is the same as for IPv4, but addresses are longer. - * Thus we must use twothirdsMD4Transform. - */ - - memcpy(hash, saddr, 16); - hash[4] = ((__force u16)sport << 16) + (__force u16)dport; - memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); - - seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK; - seq += keyptr->count; - - seq += ktime_to_ns(ktime_get_real()); - - return seq; -} -EXPORT_SYMBOL(secure_tcpv6_sequence_number); -#endif - -/* The code below is shamelessly stolen from secure_tcp_sequence_number(). - * All blames to Andrey V. Savochkin . - */ -__u32 secure_ip_id(__be32 daddr) -{ - struct keydata *keyptr; - __u32 hash[4]; - - keyptr = get_keyptr(); - - /* - * Pick a unique starting offset for each IP destination. - * The dest ip address is placed in the starting vector, - * which is then hashed with random data. - */ - hash[0] = (__force __u32)daddr; - hash[1] = keyptr->secret[9]; - hash[2] = keyptr->secret[10]; - hash[3] = keyptr->secret[11]; - - return half_md4_transform(hash, keyptr->secret); -} - -#ifdef CONFIG_INET - -__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, - __be16 sport, __be16 dport) -{ - __u32 seq; - __u32 hash[4]; - struct keydata *keyptr = get_keyptr(); - - /* - * Pick a unique starting offset for each TCP connection endpoints - * (saddr, daddr, sport, dport). - * Note that the words are placed into the starting vector, which is - * then mixed with a partial MD4 over random data. - */ - hash[0] = (__force u32)saddr; - hash[1] = (__force u32)daddr; - hash[2] = ((__force u16)sport << 16) + (__force u16)dport; - hash[3] = keyptr->secret[11]; - - seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK; - seq += keyptr->count; - /* - * As close as possible to RFC 793, which - * suggests using a 250 kHz clock. - * Further reading shows this assumes 2 Mb/s networks. - * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate. - * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but - * we also need to limit the resolution so that the u32 seq - * overlaps less than one time per MSL (2 minutes). - * Choosing a clock of 64 ns period is OK. (period of 274 s) - */ - seq += ktime_to_ns(ktime_get_real()) >> 6; - - return seq; -} - -/* Generate secure starting point for ephemeral IPV4 transport port search */ -u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) -{ - struct keydata *keyptr = get_keyptr(); - u32 hash[4]; - - /* - * Pick a unique starting offset for each ephemeral port search - * (saddr, daddr, dport) and 48bits of random data. - */ - hash[0] = (__force u32)saddr; - hash[1] = (__force u32)daddr; - hash[2] = (__force u32)dport ^ keyptr->secret[10]; - hash[3] = keyptr->secret[11]; - - return half_md4_transform(hash, keyptr->secret); -} -EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral); - -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, - __be16 dport) -{ - struct keydata *keyptr = get_keyptr(); - u32 hash[12]; - - memcpy(hash, saddr, 16); - hash[4] = (__force u32)dport; - memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); - - return twothirdsMD4Transform((const __u32 *)daddr, hash); -} -#endif - -#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE) -/* Similar to secure_tcp_sequence_number but generate a 48 bit value - * bit's 32-47 increase every key exchange - * 0-31 hash(source, dest) - */ -u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, - __be16 sport, __be16 dport) -{ - u64 seq; - __u32 hash[4]; - struct keydata *keyptr = get_keyptr(); - - hash[0] = (__force u32)saddr; - hash[1] = (__force u32)daddr; - hash[2] = ((__force u16)sport << 16) + (__force u16)dport; - hash[3] = keyptr->secret[11]; - - seq = half_md4_transform(hash, keyptr->secret); - seq |= ((u64)keyptr->count) << (32 - HASH_BITS); - - seq += ktime_to_ns(ktime_get_real()); - seq &= (1ull << 48) - 1; - - return seq; -} -EXPORT_SYMBOL(secure_dccp_sequence_number); -#endif - -#endif /* CONFIG_INET */ - - -/* - * Get a random word for internal kernel use only. Similar to urandom but - * with the goal of minimal entropy pool depletion. As a result, the random - * value is not cryptographically secure but for several uses the cost of - * depleting entropy is too high - */ -unsigned int get_random_int(void) -{ - /* - * Use IP's RNG. It suits our purpose perfectly: it re-keys itself - * every second, from the entropy pool (and thus creates a limited - * drain on it), and uses halfMD4Transform within the second. We - * also mix it with jiffies and the PID: - */ - return secure_ip_id((__force __be32)(current->pid + jiffies)); -} - -/* - * randomize_range() returns a start address such that - * - * [...... .....] - * start end - * - * a with size "len" starting at the return value is inside in the - * area defined by [start, end], but is otherwise randomized. - */ -unsigned long -randomize_range(unsigned long start, unsigned long end, unsigned long len) -{ - unsigned long range = end - len - start; - - if (end <= start + len) - return 0; - return PAGE_ALIGN(get_random_int() % range + start); -} diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile index 36af1365..ed53fdeb 100644 --- a/libdde_linux26/lib/src/Makefile +++ b/libdde_linux26/lib/src/Makefile @@ -144,7 +144,8 @@ SRC_C_libdde_linux26.o.a += \ drivers/pci/probe.c \ drivers/pci/search.c \ drivers/pci/setup-bus.c \ - drivers/pci/setup-res.c + drivers/pci/setup-res.c \ + drivers/char/random.c ################################################################## # Sources for libdde_linux_net.a # diff --git a/libdde_linux26/lib/src/drivers/char/random.c b/libdde_linux26/lib/src/drivers/char/random.c new file mode 100644 index 00000000..0430c9d0 --- /dev/null +++ b/libdde_linux26/lib/src/drivers/char/random.c @@ -0,0 +1,1709 @@ +/* + * random.c -- A strong random number generator + * + * Copyright Matt Mackall , 2003, 2004, 2005 + * + * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU General Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +/* + * (now, with legal B.S. out of the way.....) + * + * This routine gathers environmental noise from device drivers, etc., + * and returns good random numbers, suitable for cryptographic use. + * Besides the obvious cryptographic uses, these numbers are also good + * for seeding TCP sequence numbers, and other places where it is + * desirable to have numbers which are not only random, but hard to + * predict by an attacker. + * + * Theory of operation + * =================== + * + * Computers are very predictable devices. Hence it is extremely hard + * to produce truly random numbers on a computer --- as opposed to + * pseudo-random numbers, which can easily generated by using a + * algorithm. Unfortunately, it is very easy for attackers to guess + * the sequence of pseudo-random number generators, and for some + * applications this is not acceptable. So instead, we must try to + * gather "environmental noise" from the computer's environment, which + * must be hard for outside attackers to observe, and use that to + * generate random numbers. In a Unix environment, this is best done + * from inside the kernel. + * + * Sources of randomness from the environment include inter-keyboard + * timings, inter-interrupt timings from some interrupts, and other + * events which are both (a) non-deterministic and (b) hard for an + * outside observer to measure. Randomness from these sources are + * added to an "entropy pool", which is mixed using a CRC-like function. + * This is not cryptographically strong, but it is adequate assuming + * the randomness is not chosen maliciously, and it is fast enough that + * the overhead of doing it on every interrupt is very reasonable. + * As random bytes are mixed into the entropy pool, the routines keep + * an *estimate* of how many bits of randomness have been stored into + * the random number generator's internal state. + * + * When random bytes are desired, they are obtained by taking the SHA + * hash of the contents of the "entropy pool". The SHA hash avoids + * exposing the internal state of the entropy pool. It is believed to + * be computationally infeasible to derive any useful information + * about the input of SHA from its output. Even if it is possible to + * analyze SHA in some clever way, as long as the amount of data + * returned from the generator is less than the inherent entropy in + * the pool, the output data is totally unpredictable. For this + * reason, the routine decreases its internal estimate of how many + * bits of "true randomness" are contained in the entropy pool as it + * outputs random numbers. + * + * If this estimate goes to zero, the routine can still generate + * random numbers; however, an attacker may (at least in theory) be + * able to infer the future output of the generator from prior + * outputs. This requires successful cryptanalysis of SHA, which is + * not believed to be feasible, but there is a remote possibility. + * Nonetheless, these numbers should be useful for the vast majority + * of purposes. + * + * Exported interfaces ---- output + * =============================== + * + * There are three exported interfaces; the first is one designed to + * be used from within the kernel: + * + * void get_random_bytes(void *buf, int nbytes); + * + * This interface will return the requested number of random bytes, + * and place it in the requested buffer. + * + * The two other interfaces are two character devices /dev/random and + * /dev/urandom. /dev/random is suitable for use when very high + * quality randomness is desired (for example, for key generation or + * one-time pads), as it will only return a maximum of the number of + * bits of randomness (as estimated by the random number generator) + * contained in the entropy pool. + * + * The /dev/urandom device does not have this limit, and will return + * as many bytes as are requested. As more and more random bytes are + * requested without giving time for the entropy pool to recharge, + * this will result in random numbers that are merely cryptographically + * strong. For many applications, however, this is acceptable. + * + * Exported interfaces ---- input + * ============================== + * + * The current exported interfaces for gathering environmental noise + * from the devices are: + * + * void add_input_randomness(unsigned int type, unsigned int code, + * unsigned int value); + * void add_interrupt_randomness(int irq); + * + * add_input_randomness() uses the input layer interrupt timing, as well as + * the event type information from the hardware. + * + * add_interrupt_randomness() uses the inter-interrupt timing as random + * inputs to the entropy pool. Note that not all interrupts are good + * sources of randomness! For example, the timer interrupts is not a + * good choice, because the periodicity of the interrupts is too + * regular, and hence predictable to an attacker. Disk interrupts are + * a better measure, since the timing of the disk interrupts are more + * unpredictable. + * + * All of these routines try to estimate how many bits of randomness a + * particular randomness source. They do this by keeping track of the + * first and second order deltas of the event timings. + * + * Ensuring unpredictability at system startup + * ============================================ + * + * When any operating system starts up, it will go through a sequence + * of actions that are fairly predictable by an adversary, especially + * if the start-up does not involve interaction with a human operator. + * This reduces the actual number of bits of unpredictability in the + * entropy pool below the value in entropy_count. In order to + * counteract this effect, it helps to carry information in the + * entropy pool across shut-downs and start-ups. To do this, put the + * following lines an appropriate script which is run during the boot + * sequence: + * + * echo "Initializing random number generator..." + * random_seed=/var/run/random-seed + * # Carry a random seed from start-up to start-up + * # Load and then save the whole entropy pool + * if [ -f $random_seed ]; then + * cat $random_seed >/dev/urandom + * else + * touch $random_seed + * fi + * chmod 600 $random_seed + * dd if=/dev/urandom of=$random_seed count=1 bs=512 + * + * and the following lines in an appropriate script which is run as + * the system is shutdown: + * + * # Carry a random seed from shut-down to start-up + * # Save the whole entropy pool + * echo "Saving random seed..." + * random_seed=/var/run/random-seed + * touch $random_seed + * chmod 600 $random_seed + * dd if=/dev/urandom of=$random_seed count=1 bs=512 + * + * For example, on most modern systems using the System V init + * scripts, such code fragments would be found in + * /etc/rc.d/init.d/random. On older Linux systems, the correct script + * location might be in /etc/rcb.d/rc.local or /etc/rc.d/rc.0. + * + * Effectively, these commands cause the contents of the entropy pool + * to be saved at shut-down time and reloaded into the entropy pool at + * start-up. (The 'dd' in the addition to the bootup script is to + * make sure that /etc/random-seed is different for every start-up, + * even if the system crashes without executing rc.0.) Even with + * complete knowledge of the start-up activities, predicting the state + * of the entropy pool requires knowledge of the previous history of + * the system. + * + * Configuring the /dev/random driver under Linux + * ============================================== + * + * The /dev/random driver under Linux uses minor numbers 8 and 9 of + * the /dev/mem major number (#1). So if your system does not have + * /dev/random and /dev/urandom created already, they can be created + * by using the commands: + * + * mknod /dev/random c 1 8 + * mknod /dev/urandom c 1 9 + * + * Acknowledgements: + * ================= + * + * Ideas for constructing this random number generator were derived + * from Pretty Good Privacy's random number generator, and from private + * discussions with Phil Karn. Colin Plumb provided a faster random + * number generator, which speed up the mixing function of the entropy + * pool, taken from PGPfone. Dale Worley has also contributed many + * useful ideas and suggestions to improve this driver. + * + * Any flaws in the design are solely my responsibility, and should + * not be attributed to the Phil, Colin, or any of authors of PGP. + * + * Further background information on this topic may be obtained from + * RFC 1750, "Randomness Recommendations for Security", by Donald + * Eastlake, Steve Crocker, and Jeff Schiller. + */ + +#ifdef DDE_LINUX +#include +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Configuration information + */ +#define INPUT_POOL_WORDS 128 +#define OUTPUT_POOL_WORDS 32 +#define SEC_XFER_SIZE 512 + +/* + * The minimum number of bits of entropy before we wake up a read on + * /dev/random. Should be enough to do a significant reseed. + */ +static int random_read_wakeup_thresh = 64; + +/* + * If the entropy count falls under this number of bits, then we + * should wake up processes which are selecting or polling on write + * access to /dev/random. + */ +static int random_write_wakeup_thresh = 128; + +/* + * When the input pool goes over trickle_thresh, start dropping most + * samples to avoid wasting CPU time and reduce lock contention. + */ + +static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28; + +static DEFINE_PER_CPU(int, trickle_count); + +/* + * A pool of size .poolwords is stirred with a primitive polynomial + * of degree .poolwords over GF(2). The taps for various sizes are + * defined below. They are chosen to be evenly spaced (minimum RMS + * distance from evenly spaced; the numbers in the comments are a + * scaled squared error sum) except for the last tap, which is 1 to + * get the twisting happening as fast as possible. + */ +static struct poolinfo { + int poolwords; + int tap1, tap2, tap3, tap4, tap5; +} poolinfo_table[] = { + /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */ + { 128, 103, 76, 51, 25, 1 }, + /* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */ + { 32, 26, 20, 14, 7, 1 }, +#if 0 + /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */ + { 2048, 1638, 1231, 819, 411, 1 }, + + /* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */ + { 1024, 817, 615, 412, 204, 1 }, + + /* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */ + { 1024, 819, 616, 410, 207, 2 }, + + /* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */ + { 512, 411, 308, 208, 104, 1 }, + + /* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */ + { 512, 409, 307, 206, 102, 2 }, + /* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */ + { 512, 409, 309, 205, 103, 2 }, + + /* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */ + { 256, 205, 155, 101, 52, 1 }, + + /* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */ + { 128, 103, 78, 51, 27, 2 }, + + /* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */ + { 64, 52, 39, 26, 14, 1 }, +#endif +}; + +#define POOLBITS poolwords*32 +#define POOLBYTES poolwords*4 + +/* + * For the purposes of better mixing, we use the CRC-32 polynomial as + * well to make a twisted Generalized Feedback Shift Reigster + * + * (See M. Matsumoto & Y. Kurita, 1992. Twisted GFSR generators. ACM + * Transactions on Modeling and Computer Simulation 2(3):179-194. + * Also see M. Matsumoto & Y. Kurita, 1994. Twisted GFSR generators + * II. ACM Transactions on Mdeling and Computer Simulation 4:254-266) + * + * Thanks to Colin Plumb for suggesting this. + * + * We have not analyzed the resultant polynomial to prove it primitive; + * in fact it almost certainly isn't. Nonetheless, the irreducible factors + * of a random large-degree polynomial over GF(2) are more than large enough + * that periodicity is not a concern. + * + * The input hash is much less sensitive than the output hash. All + * that we want of it is that it be a good non-cryptographic hash; + * i.e. it not produce collisions when fed "random" data of the sort + * we expect to see. As long as the pool state differs for different + * inputs, we have preserved the input entropy and done a good job. + * The fact that an intelligent attacker can construct inputs that + * will produce controlled alterations to the pool's state is not + * important because we don't consider such inputs to contribute any + * randomness. The only property we need with respect to them is that + * the attacker can't increase his/her knowledge of the pool's state. + * Since all additions are reversible (knowing the final state and the + * input, you can reconstruct the initial state), if an attacker has + * any uncertainty about the initial state, he/she can only shuffle + * that uncertainty about, but never cause any collisions (which would + * decrease the uncertainty). + * + * The chosen system lets the state of the pool be (essentially) the input + * modulo the generator polymnomial. Now, for random primitive polynomials, + * this is a universal class of hash functions, meaning that the chance + * of a collision is limited by the attacker's knowledge of the generator + * polynomail, so if it is chosen at random, an attacker can never force + * a collision. Here, we use a fixed polynomial, but we *can* assume that + * ###--> it is unknown to the processes generating the input entropy. <-### + * Because of this important property, this is a good, collision-resistant + * hash; hash collisions will occur no more often than chance. + */ + +/* + * Static global variables + */ +static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); +static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); +static struct fasync_struct *fasync; + +#if 0 +static int debug; +module_param(debug, bool, 0644); +#define DEBUG_ENT(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG "random %04d %04d %04d: " \ + fmt,\ + input_pool.entropy_count,\ + blocking_pool.entropy_count,\ + nonblocking_pool.entropy_count,\ + ## arg); } while (0) +#else +#define DEBUG_ENT(fmt, arg...) do {} while (0) +#endif + +/********************************************************************** + * + * OS independent entropy store. Here are the functions which handle + * storing entropy in an entropy pool. + * + **********************************************************************/ + +struct entropy_store; +struct entropy_store { + /* read-only data: */ + struct poolinfo *poolinfo; + __u32 *pool; + const char *name; + int limit; + struct entropy_store *pull; + + /* read-write data: */ + spinlock_t lock; + unsigned add_ptr; + int entropy_count; + int input_rotate; +}; + +static __u32 input_pool_data[INPUT_POOL_WORDS]; +static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; +static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS]; + +static struct entropy_store input_pool = { + .poolinfo = &poolinfo_table[0], + .name = "input", + .limit = 1, + .lock = __SPIN_LOCK_UNLOCKED(&input_pool.lock), + .pool = input_pool_data +}; + +static struct entropy_store blocking_pool = { + .poolinfo = &poolinfo_table[1], + .name = "blocking", + .limit = 1, + .pull = &input_pool, + .lock = __SPIN_LOCK_UNLOCKED(&blocking_pool.lock), + .pool = blocking_pool_data +}; + +static struct entropy_store nonblocking_pool = { + .poolinfo = &poolinfo_table[1], + .name = "nonblocking", + .pull = &input_pool, + .lock = __SPIN_LOCK_UNLOCKED(&nonblocking_pool.lock), + .pool = nonblocking_pool_data +}; + +/* + * This function adds bytes into the entropy "pool". It does not + * update the entropy estimate. The caller should call + * credit_entropy_bits if this is appropriate. + * + * The pool is stirred with a primitive polynomial of the appropriate + * degree, and then twisted. We twist by three bits at a time because + * it's cheap to do so and helps slightly in the expected case where + * the entropy is concentrated in the low-order bits. + */ +static void mix_pool_bytes_extract(struct entropy_store *r, const void *in, + int nbytes, __u8 out[64]) +{ + static __u32 const twist_table[8] = { + 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, + 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; + unsigned long i, j, tap1, tap2, tap3, tap4, tap5; + int input_rotate; + int wordmask = r->poolinfo->poolwords - 1; + const char *bytes = in; + __u32 w; + unsigned long flags; + + /* Taps are constant, so we can load them without holding r->lock. */ + tap1 = r->poolinfo->tap1; + tap2 = r->poolinfo->tap2; + tap3 = r->poolinfo->tap3; + tap4 = r->poolinfo->tap4; + tap5 = r->poolinfo->tap5; + + spin_lock_irqsave(&r->lock, flags); + input_rotate = r->input_rotate; + i = r->add_ptr; + + /* mix one byte at a time to simplify size handling and churn faster */ + while (nbytes--) { + w = rol32(*bytes++, input_rotate & 31); + i = (i - 1) & wordmask; + + /* XOR in the various taps */ + w ^= r->pool[i]; + w ^= r->pool[(i + tap1) & wordmask]; + w ^= r->pool[(i + tap2) & wordmask]; + w ^= r->pool[(i + tap3) & wordmask]; + w ^= r->pool[(i + tap4) & wordmask]; + w ^= r->pool[(i + tap5) & wordmask]; + + /* Mix the result back in with a twist */ + r->pool[i] = (w >> 3) ^ twist_table[w & 7]; + + /* + * Normally, we add 7 bits of rotation to the pool. + * At the beginning of the pool, add an extra 7 bits + * rotation, so that successive passes spread the + * input bits across the pool evenly. + */ + input_rotate += i ? 7 : 14; + } + + r->input_rotate = input_rotate; + r->add_ptr = i; + + if (out) + for (j = 0; j < 16; j++) + ((__u32 *)out)[j] = r->pool[(i - j) & wordmask]; + + spin_unlock_irqrestore(&r->lock, flags); +} + +static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes) +{ + mix_pool_bytes_extract(r, in, bytes, NULL); +} + +/* + * Credit (or debit) the entropy store with n bits of entropy + */ +static void credit_entropy_bits(struct entropy_store *r, int nbits) +{ + unsigned long flags; + int entropy_count; + + if (!nbits) + return; + + spin_lock_irqsave(&r->lock, flags); + + DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); + entropy_count = r->entropy_count; + entropy_count += nbits; + if (entropy_count < 0) { + DEBUG_ENT("negative entropy/overflow\n"); + entropy_count = 0; + } else if (entropy_count > r->poolinfo->POOLBITS) + entropy_count = r->poolinfo->POOLBITS; + r->entropy_count = entropy_count; + + /* should we wake readers? */ + if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) { + wake_up_interruptible(&random_read_wait); + kill_fasync(&fasync, SIGIO, POLL_IN); + } + spin_unlock_irqrestore(&r->lock, flags); +} + +/********************************************************************* + * + * Entropy input management + * + *********************************************************************/ + +/* There is one of these per entropy source */ +struct timer_rand_state { + cycles_t last_time; + long last_delta, last_delta2; + unsigned dont_count_entropy:1; +}; + +#ifndef CONFIG_SPARSE_IRQ + +static struct timer_rand_state *irq_timer_state[NR_IRQS]; + +static struct timer_rand_state *get_timer_rand_state(unsigned int irq) +{ + return irq_timer_state[irq]; +} + +static void set_timer_rand_state(unsigned int irq, + struct timer_rand_state *state) +{ + irq_timer_state[irq] = state; +} + +#else + +static struct timer_rand_state *get_timer_rand_state(unsigned int irq) +{ + struct irq_desc *desc; + + desc = irq_to_desc(irq); + + return desc->timer_rand_state; +} + +static void set_timer_rand_state(unsigned int irq, + struct timer_rand_state *state) +{ + struct irq_desc *desc; + + desc = irq_to_desc(irq); + + desc->timer_rand_state = state; +} +#endif + +static struct timer_rand_state input_timer_state; + +/* + * This function adds entropy to the entropy "pool" by using timing + * delays. It uses the timer_rand_state structure to make an estimate + * of how many bits of entropy this call has added to the pool. + * + * The number "num" is also added to the pool - it should somehow describe + * the type of event which just happened. This is currently 0-255 for + * keyboard scan codes, and 256 upwards for interrupts. + * + */ +static void add_timer_randomness(struct timer_rand_state *state, unsigned num) +{ + struct { + cycles_t cycles; + long jiffies; + unsigned num; + } sample; + long delta, delta2, delta3; + + preempt_disable(); + /* if over the trickle threshold, use only 1 in 4096 samples */ + if (input_pool.entropy_count > trickle_thresh && + (__get_cpu_var(trickle_count)++ & 0xfff)) + goto out; + + sample.jiffies = jiffies; + sample.cycles = get_cycles(); + sample.num = num; + mix_pool_bytes(&input_pool, &sample, sizeof(sample)); + + /* + * Calculate number of bits of randomness we probably added. + * We take into account the first, second and third-order deltas + * in order to make our estimate. + */ + + if (!state->dont_count_entropy) { + delta = sample.jiffies - state->last_time; + state->last_time = sample.jiffies; + + delta2 = delta - state->last_delta; + state->last_delta = delta; + + delta3 = delta2 - state->last_delta2; + state->last_delta2 = delta2; + + if (delta < 0) + delta = -delta; + if (delta2 < 0) + delta2 = -delta2; + if (delta3 < 0) + delta3 = -delta3; + if (delta > delta2) + delta = delta2; + if (delta > delta3) + delta = delta3; + + /* + * delta is now minimum absolute delta. + * Round down by 1 bit on general principles, + * and limit entropy entimate to 12 bits. + */ + credit_entropy_bits(&input_pool, + min_t(int, fls(delta>>1), 11)); + } +out: + preempt_enable(); +} + +void add_input_randomness(unsigned int type, unsigned int code, + unsigned int value) +{ + static unsigned char last_value; + + /* ignore autorepeat and the like */ + if (value == last_value) + return; + + DEBUG_ENT("input event\n"); + last_value = value; + add_timer_randomness(&input_timer_state, + (type << 4) ^ code ^ (code >> 4) ^ value); +} +EXPORT_SYMBOL_GPL(add_input_randomness); + +void add_interrupt_randomness(int irq) +{ + struct timer_rand_state *state; + + state = get_timer_rand_state(irq); + + if (state == NULL) + return; + + DEBUG_ENT("irq event %d\n", irq); + add_timer_randomness(state, 0x100 + irq); +} + +#ifdef CONFIG_BLOCK +void add_disk_randomness(struct gendisk *disk) +{ + if (!disk || !disk->random) + return; + /* first major is 1, so we get >= 0x200 here */ + DEBUG_ENT("disk event %d:%d\n", + MAJOR(disk_devt(disk)), MINOR(disk_devt(disk))); + + add_timer_randomness(disk->random, 0x100 + disk_devt(disk)); +} +#endif + +#define EXTRACT_SIZE 10 + +/********************************************************************* + * + * Entropy extraction routines + * + *********************************************************************/ + +static ssize_t extract_entropy(struct entropy_store *r, void *buf, + size_t nbytes, int min, int rsvd); + +/* + * This utility inline function is responsible for transfering entropy + * from the primary pool to the secondary extraction pool. We make + * sure we pull enough for a 'catastrophic reseed'. + */ +static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) +{ + __u32 tmp[OUTPUT_POOL_WORDS]; + + if (r->pull && r->entropy_count < nbytes * 8 && + r->entropy_count < r->poolinfo->POOLBITS) { + /* If we're limited, always leave two wakeup worth's BITS */ + int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; + int bytes = nbytes; + + /* pull at least as many as BYTES as wakeup BITS */ + bytes = max_t(int, bytes, random_read_wakeup_thresh / 8); + /* but never more than the buffer size */ + bytes = min_t(int, bytes, sizeof(tmp)); + + DEBUG_ENT("going to reseed %s with %d bits " + "(%d of %d requested)\n", + r->name, bytes * 8, nbytes * 8, r->entropy_count); + + bytes = extract_entropy(r->pull, tmp, bytes, + random_read_wakeup_thresh / 8, rsvd); + mix_pool_bytes(r, tmp, bytes); + credit_entropy_bits(r, bytes*8); + } +} + +/* + * These functions extracts randomness from the "entropy pool", and + * returns it in a buffer. + * + * The min parameter specifies the minimum amount we can pull before + * failing to avoid races that defeat catastrophic reseeding while the + * reserved parameter indicates how much entropy we must leave in the + * pool after each pull to avoid starving other readers. + * + * Note: extract_entropy() assumes that .poolwords is a multiple of 16 words. + */ + +static size_t account(struct entropy_store *r, size_t nbytes, int min, + int reserved) +{ + unsigned long flags; + + /* Hold lock while accounting */ + spin_lock_irqsave(&r->lock, flags); + + BUG_ON(r->entropy_count > r->poolinfo->POOLBITS); + DEBUG_ENT("trying to extract %d bits from %s\n", + nbytes * 8, r->name); + + /* Can we pull enough? */ + if (r->entropy_count / 8 < min + reserved) { + nbytes = 0; + } else { + /* If limited, never pull more than available */ + if (r->limit && nbytes + reserved >= r->entropy_count / 8) + nbytes = r->entropy_count/8 - reserved; + + if (r->entropy_count / 8 >= nbytes + reserved) + r->entropy_count -= nbytes*8; + else + r->entropy_count = reserved; + + if (r->entropy_count < random_write_wakeup_thresh) { + wake_up_interruptible(&random_write_wait); + kill_fasync(&fasync, SIGIO, POLL_OUT); + } + } + + DEBUG_ENT("debiting %d entropy credits from %s%s\n", + nbytes * 8, r->name, r->limit ? "" : " (unlimited)"); + + spin_unlock_irqrestore(&r->lock, flags); + + return nbytes; +} + +static void extract_buf(struct entropy_store *r, __u8 *out) +{ + int i; + __u32 hash[5], workspace[SHA_WORKSPACE_WORDS]; + __u8 extract[64]; + + /* Generate a hash across the pool, 16 words (512 bits) at a time */ + sha_init(hash); + for (i = 0; i < r->poolinfo->poolwords; i += 16) + sha_transform(hash, (__u8 *)(r->pool + i), workspace); + + /* + * We mix the hash back into the pool to prevent backtracking + * attacks (where the attacker knows the state of the pool + * plus the current outputs, and attempts to find previous + * ouputs), unless the hash function can be inverted. By + * mixing at least a SHA1 worth of hash data back, we make + * brute-forcing the feedback as hard as brute-forcing the + * hash. + */ + mix_pool_bytes_extract(r, hash, sizeof(hash), extract); + + /* + * To avoid duplicates, we atomically extract a portion of the + * pool while mixing, and hash one final time. + */ + sha_transform(hash, extract, workspace); + memset(extract, 0, sizeof(extract)); + memset(workspace, 0, sizeof(workspace)); + + /* + * In case the hash function has some recognizable output + * pattern, we fold it in half. Thus, we always feed back + * twice as much data as we output. + */ + hash[0] ^= hash[3]; + hash[1] ^= hash[4]; + hash[2] ^= rol32(hash[2], 16); + memcpy(out, hash, EXTRACT_SIZE); + memset(hash, 0, sizeof(hash)); +} + +static ssize_t extract_entropy(struct entropy_store *r, void *buf, + size_t nbytes, int min, int reserved) +{ + ssize_t ret = 0, i; + __u8 tmp[EXTRACT_SIZE]; + + xfer_secondary_pool(r, nbytes); + nbytes = account(r, nbytes, min, reserved); + + while (nbytes) { + extract_buf(r, tmp); + i = min_t(int, nbytes, EXTRACT_SIZE); + memcpy(buf, tmp, i); + nbytes -= i; + buf += i; + ret += i; + } + + /* Wipe data just returned from memory */ + memset(tmp, 0, sizeof(tmp)); + + return ret; +} + +static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, + size_t nbytes) +{ + ssize_t ret = 0, i; + __u8 tmp[EXTRACT_SIZE]; + + xfer_secondary_pool(r, nbytes); + nbytes = account(r, nbytes, 0, 0); + + while (nbytes) { + if (need_resched()) { + if (signal_pending(current)) { + if (ret == 0) + ret = -ERESTARTSYS; + break; + } + schedule(); + } + + extract_buf(r, tmp); + i = min_t(int, nbytes, EXTRACT_SIZE); + if (copy_to_user(buf, tmp, i)) { + ret = -EFAULT; + break; + } + + nbytes -= i; + buf += i; + ret += i; + } + + /* Wipe data just returned from memory */ + memset(tmp, 0, sizeof(tmp)); + + return ret; +} + +#endif + +/* + * This function is the exported kernel interface. It returns some + * number of good random numbers, suitable for seeding TCP sequence + * numbers, etc. + */ +void get_random_bytes(void *buf, int nbytes) +{ +#ifndef DDE_LINUX + extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0); +#else + int i; + int nlwords = nbytes / sizeof (long); + for (i = 0; i < nlwords; i++) + ((long *) buf)[i] = ddekit_random (); + for (i = nlwords * sizeof (long); i < nbytes; i++) + ((char *) buf)[i] = (char) ddekit_random (); +#endif +} +EXPORT_SYMBOL(get_random_bytes); + +#ifndef DDE_LINUX +/* + * init_std_data - initialize pool with system data + * + * @r: pool to initialize + * + * This function clears the pool's entropy count and mixes some system + * data into the pool to prepare it for use. The pool is not cleared + * as that can only decrease the entropy in the pool. + */ +static void init_std_data(struct entropy_store *r) +{ + ktime_t now; + unsigned long flags; + + spin_lock_irqsave(&r->lock, flags); + r->entropy_count = 0; + spin_unlock_irqrestore(&r->lock, flags); + + now = ktime_get_real(); + mix_pool_bytes(r, &now, sizeof(now)); + mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); +} + +static int rand_initialize(void) +{ + init_std_data(&input_pool); + init_std_data(&blocking_pool); + init_std_data(&nonblocking_pool); + return 0; +} +module_init(rand_initialize); + +void rand_initialize_irq(int irq) +{ + struct timer_rand_state *state; + + state = get_timer_rand_state(irq); + + if (state) + return; + + /* + * If kzalloc returns null, we just won't use that entropy + * source. + */ + state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); + if (state) + set_timer_rand_state(irq, state); +} + +#ifdef CONFIG_BLOCK +void rand_initialize_disk(struct gendisk *disk) +{ + struct timer_rand_state *state; + + /* + * If kzalloc returns null, we just won't use that entropy + * source. + */ + state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); + if (state) + disk->random = state; +} +#endif + +static ssize_t +random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) +{ + ssize_t n, retval = 0, count = 0; + + if (nbytes == 0) + return 0; + + while (nbytes > 0) { + n = nbytes; + if (n > SEC_XFER_SIZE) + n = SEC_XFER_SIZE; + + DEBUG_ENT("reading %d bits\n", n*8); + + n = extract_entropy_user(&blocking_pool, buf, n); + + DEBUG_ENT("read got %d bits (%d still needed)\n", + n*8, (nbytes-n)*8); + + if (n == 0) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + + DEBUG_ENT("sleeping?\n"); + + wait_event_interruptible(random_read_wait, + input_pool.entropy_count >= + random_read_wakeup_thresh); + + DEBUG_ENT("awake\n"); + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + continue; + } + + if (n < 0) { + retval = n; + break; + } + count += n; + buf += n; + nbytes -= n; + break; /* This break makes the device work */ + /* like a named pipe */ + } + + /* + * If we gave the user some bytes, update the access time. + */ + if (count) + file_accessed(file); + + return (count ? count : retval); +} + +static ssize_t +urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) +{ + return extract_entropy_user(&nonblocking_pool, buf, nbytes); +} + +static unsigned int +random_poll(struct file *file, poll_table * wait) +{ + unsigned int mask; + + poll_wait(file, &random_read_wait, wait); + poll_wait(file, &random_write_wait, wait); + mask = 0; + if (input_pool.entropy_count >= random_read_wakeup_thresh) + mask |= POLLIN | POLLRDNORM; + if (input_pool.entropy_count < random_write_wakeup_thresh) + mask |= POLLOUT | POLLWRNORM; + return mask; +} + +static int +write_pool(struct entropy_store *r, const char __user *buffer, size_t count) +{ + size_t bytes; + __u32 buf[16]; + const char __user *p = buffer; + + while (count > 0) { + bytes = min(count, sizeof(buf)); + if (copy_from_user(&buf, p, bytes)) + return -EFAULT; + + count -= bytes; + p += bytes; + + mix_pool_bytes(r, buf, bytes); + cond_resched(); + } + + return 0; +} + +static ssize_t random_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + size_t ret; + struct inode *inode = file->f_path.dentry->d_inode; + + ret = write_pool(&blocking_pool, buffer, count); + if (ret) + return ret; + ret = write_pool(&nonblocking_pool, buffer, count); + if (ret) + return ret; + + inode->i_mtime = current_fs_time(inode->i_sb); + mark_inode_dirty(inode); + return (ssize_t)count; +} + +static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) +{ + int size, ent_count; + int __user *p = (int __user *)arg; + int retval; + + switch (cmd) { + case RNDGETENTCNT: + /* inherently racy, no point locking */ + if (put_user(input_pool.entropy_count, p)) + return -EFAULT; + return 0; + case RNDADDTOENTCNT: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (get_user(ent_count, p)) + return -EFAULT; + credit_entropy_bits(&input_pool, ent_count); + return 0; + case RNDADDENTROPY: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (get_user(ent_count, p++)) + return -EFAULT; + if (ent_count < 0) + return -EINVAL; + if (get_user(size, p++)) + return -EFAULT; + retval = write_pool(&input_pool, (const char __user *)p, + size); + if (retval < 0) + return retval; + credit_entropy_bits(&input_pool, ent_count); + return 0; + case RNDZAPENTCNT: + case RNDCLEARPOOL: + /* Clear the entropy pool counters. */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + rand_initialize(); + return 0; + default: + return -EINVAL; + } +} + +static int random_fasync(int fd, struct file *filp, int on) +{ + return fasync_helper(fd, filp, on, &fasync); +} + +const struct file_operations random_fops = { + .read = random_read, + .write = random_write, + .poll = random_poll, + .unlocked_ioctl = random_ioctl, + .fasync = random_fasync, +}; + +const struct file_operations urandom_fops = { + .read = urandom_read, + .write = random_write, + .unlocked_ioctl = random_ioctl, + .fasync = random_fasync, +}; + +/*************************************************************** + * Random UUID interface + * + * Used here for a Boot ID, but can be useful for other kernel + * drivers. + ***************************************************************/ + +/* + * Generate random UUID + */ +void generate_random_uuid(unsigned char uuid_out[16]) +{ + get_random_bytes(uuid_out, 16); + /* Set UUID version to 4 --- truely random generation */ + uuid_out[6] = (uuid_out[6] & 0x0F) | 0x40; + /* Set the UUID variant to DCE */ + uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80; +} +EXPORT_SYMBOL(generate_random_uuid); + +/******************************************************************** + * + * Sysctl interface + * + ********************************************************************/ + +#ifdef CONFIG_SYSCTL + +#include + +static int min_read_thresh = 8, min_write_thresh; +static int max_read_thresh = INPUT_POOL_WORDS * 32; +static int max_write_thresh = INPUT_POOL_WORDS * 32; +static char sysctl_bootid[16]; + +/* + * These functions is used to return both the bootid UUID, and random + * UUID. The difference is in whether table->data is NULL; if it is, + * then a new UUID is generated and returned to the user. + * + * If the user accesses this via the proc interface, it will be returned + * as an ASCII string in the standard UUID format. If accesses via the + * sysctl system call, it is returned as 16 bytes of binary data. + */ +static int proc_do_uuid(ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + ctl_table fake_table; + unsigned char buf[64], tmp_uuid[16], *uuid; + + uuid = table->data; + if (!uuid) { + uuid = tmp_uuid; + uuid[8] = 0; + } + if (uuid[8] == 0) + generate_random_uuid(uuid); + + sprintf(buf, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x%02x%02x%02x%02x", + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); + fake_table.data = buf; + fake_table.maxlen = sizeof(buf); + + return proc_dostring(&fake_table, write, filp, buffer, lenp, ppos); +} + +static int uuid_strategy(ctl_table *table, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen) +{ + unsigned char tmp_uuid[16], *uuid; + unsigned int len; + + if (!oldval || !oldlenp) + return 1; + + uuid = table->data; + if (!uuid) { + uuid = tmp_uuid; + uuid[8] = 0; + } + if (uuid[8] == 0) + generate_random_uuid(uuid); + + if (get_user(len, oldlenp)) + return -EFAULT; + if (len) { + if (len > 16) + len = 16; + if (copy_to_user(oldval, uuid, len) || + put_user(len, oldlenp)) + return -EFAULT; + } + return 1; +} + +static int sysctl_poolsize = INPUT_POOL_WORDS * 32; +ctl_table random_table[] = { + { + .ctl_name = RANDOM_POOLSIZE, + .procname = "poolsize", + .data = &sysctl_poolsize, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = RANDOM_ENTROPY_COUNT, + .procname = "entropy_avail", + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + .data = &input_pool.entropy_count, + }, + { + .ctl_name = RANDOM_READ_THRESH, + .procname = "read_wakeup_threshold", + .data = &random_read_wakeup_thresh, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &min_read_thresh, + .extra2 = &max_read_thresh, + }, + { + .ctl_name = RANDOM_WRITE_THRESH, + .procname = "write_wakeup_threshold", + .data = &random_write_wakeup_thresh, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &min_write_thresh, + .extra2 = &max_write_thresh, + }, + { + .ctl_name = RANDOM_BOOT_ID, + .procname = "boot_id", + .data = &sysctl_bootid, + .maxlen = 16, + .mode = 0444, + .proc_handler = &proc_do_uuid, + .strategy = &uuid_strategy, + }, + { + .ctl_name = RANDOM_UUID, + .procname = "uuid", + .maxlen = 16, + .mode = 0444, + .proc_handler = &proc_do_uuid, + .strategy = &uuid_strategy, + }, + { .ctl_name = 0 } +}; +#endif /* CONFIG_SYSCTL */ + +/******************************************************************** + * + * Random funtions for networking + * + ********************************************************************/ + +/* + * TCP initial sequence number picking. This uses the random number + * generator to pick an initial secret value. This value is hashed + * along with the TCP endpoint information to provide a unique + * starting point for each pair of TCP endpoints. This defeats + * attacks which rely on guessing the initial TCP sequence number. + * This algorithm was suggested by Steve Bellovin. + * + * Using a very strong hash was taking an appreciable amount of the total + * TCP connection establishment time, so this is a weaker hash, + * compensated for by changing the secret periodically. + */ + +/* F, G and H are basic MD4 functions: selection, majority, parity */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +/* + * The generic round function. The application is so specific that + * we don't bother protecting all the arguments with parens, as is generally + * good macro practice, in favor of extra legibility. + * Rotation is separate from addition to prevent recomputation + */ +#define ROUND(f, a, b, c, d, x, s) \ + (a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s))) +#define K1 0 +#define K2 013240474631UL +#define K3 015666365641UL + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +static __u32 twothirdsMD4Transform(__u32 const buf[4], __u32 const in[12]) +{ + __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ + ROUND(F, a, b, c, d, in[ 0] + K1, 3); + ROUND(F, d, a, b, c, in[ 1] + K1, 7); + ROUND(F, c, d, a, b, in[ 2] + K1, 11); + ROUND(F, b, c, d, a, in[ 3] + K1, 19); + ROUND(F, a, b, c, d, in[ 4] + K1, 3); + ROUND(F, d, a, b, c, in[ 5] + K1, 7); + ROUND(F, c, d, a, b, in[ 6] + K1, 11); + ROUND(F, b, c, d, a, in[ 7] + K1, 19); + ROUND(F, a, b, c, d, in[ 8] + K1, 3); + ROUND(F, d, a, b, c, in[ 9] + K1, 7); + ROUND(F, c, d, a, b, in[10] + K1, 11); + ROUND(F, b, c, d, a, in[11] + K1, 19); + + /* Round 2 */ + ROUND(G, a, b, c, d, in[ 1] + K2, 3); + ROUND(G, d, a, b, c, in[ 3] + K2, 5); + ROUND(G, c, d, a, b, in[ 5] + K2, 9); + ROUND(G, b, c, d, a, in[ 7] + K2, 13); + ROUND(G, a, b, c, d, in[ 9] + K2, 3); + ROUND(G, d, a, b, c, in[11] + K2, 5); + ROUND(G, c, d, a, b, in[ 0] + K2, 9); + ROUND(G, b, c, d, a, in[ 2] + K2, 13); + ROUND(G, a, b, c, d, in[ 4] + K2, 3); + ROUND(G, d, a, b, c, in[ 6] + K2, 5); + ROUND(G, c, d, a, b, in[ 8] + K2, 9); + ROUND(G, b, c, d, a, in[10] + K2, 13); + + /* Round 3 */ + ROUND(H, a, b, c, d, in[ 3] + K3, 3); + ROUND(H, d, a, b, c, in[ 7] + K3, 9); + ROUND(H, c, d, a, b, in[11] + K3, 11); + ROUND(H, b, c, d, a, in[ 2] + K3, 15); + ROUND(H, a, b, c, d, in[ 6] + K3, 3); + ROUND(H, d, a, b, c, in[10] + K3, 9); + ROUND(H, c, d, a, b, in[ 1] + K3, 11); + ROUND(H, b, c, d, a, in[ 5] + K3, 15); + ROUND(H, a, b, c, d, in[ 9] + K3, 3); + ROUND(H, d, a, b, c, in[ 0] + K3, 9); + ROUND(H, c, d, a, b, in[ 4] + K3, 11); + ROUND(H, b, c, d, a, in[ 8] + K3, 15); + + return buf[1] + b; /* "most hashed" word */ + /* Alternative: return sum of all words? */ +} +#endif + +#undef ROUND +#undef F +#undef G +#undef H +#undef K1 +#undef K2 +#undef K3 + +/* This should not be decreased so low that ISNs wrap too fast. */ +#define REKEY_INTERVAL (300 * HZ) +/* + * Bit layout of the tcp sequence numbers (before adding current time): + * bit 24-31: increased after every key exchange + * bit 0-23: hash(source,dest) + * + * The implementation is similar to the algorithm described + * in the Appendix of RFC 1185, except that + * - it uses a 1 MHz clock instead of a 250 kHz clock + * - it performs a rekey every 5 minutes, which is equivalent + * to a (source,dest) tulple dependent forward jump of the + * clock by 0..2^(HASH_BITS+1) + * + * Thus the average ISN wraparound time is 68 minutes instead of + * 4.55 hours. + * + * SMP cleanup and lock avoidance with poor man's RCU. + * Manfred Spraul + * + */ +#define COUNT_BITS 8 +#define COUNT_MASK ((1 << COUNT_BITS) - 1) +#define HASH_BITS 24 +#define HASH_MASK ((1 << HASH_BITS) - 1) + +static struct keydata { + __u32 count; /* already shifted to the final position */ + __u32 secret[12]; +} ____cacheline_aligned ip_keydata[2]; + +static unsigned int ip_cnt; + +static void rekey_seq_generator(struct work_struct *work); + +static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator); + +/* + * Lock avoidance: + * The ISN generation runs lockless - it's just a hash over random data. + * State changes happen every 5 minutes when the random key is replaced. + * Synchronization is performed by having two copies of the hash function + * state and rekey_seq_generator always updates the inactive copy. + * The copy is then activated by updating ip_cnt. + * The implementation breaks down if someone blocks the thread + * that processes SYN requests for more than 5 minutes. Should never + * happen, and even if that happens only a not perfectly compliant + * ISN is generated, nothing fatal. + */ +static void rekey_seq_generator(struct work_struct *work) +{ + struct keydata *keyptr = &ip_keydata[1 ^ (ip_cnt & 1)]; + + get_random_bytes(keyptr->secret, sizeof(keyptr->secret)); + keyptr->count = (ip_cnt & COUNT_MASK) << HASH_BITS; + smp_wmb(); + ip_cnt++; + schedule_delayed_work(&rekey_work, REKEY_INTERVAL); +} + +static inline struct keydata *get_keyptr(void) +{ + struct keydata *keyptr = &ip_keydata[ip_cnt & 1]; + + smp_rmb(); + + return keyptr; +} + +static __init int seqgen_init(void) +{ + rekey_seq_generator(NULL); + return 0; +} +late_initcall(seqgen_init); + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, + __be16 sport, __be16 dport) +{ + __u32 seq; + __u32 hash[12]; + struct keydata *keyptr = get_keyptr(); + + /* The procedure is the same as for IPv4, but addresses are longer. + * Thus we must use twothirdsMD4Transform. + */ + + memcpy(hash, saddr, 16); + hash[4] = ((__force u16)sport << 16) + (__force u16)dport; + memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); + + seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK; + seq += keyptr->count; + + seq += ktime_to_ns(ktime_get_real()); + + return seq; +} +EXPORT_SYMBOL(secure_tcpv6_sequence_number); +#endif + +/* The code below is shamelessly stolen from secure_tcp_sequence_number(). + * All blames to Andrey V. Savochkin . + */ +__u32 secure_ip_id(__be32 daddr) +{ + struct keydata *keyptr; + __u32 hash[4]; + + keyptr = get_keyptr(); + + /* + * Pick a unique starting offset for each IP destination. + * The dest ip address is placed in the starting vector, + * which is then hashed with random data. + */ + hash[0] = (__force __u32)daddr; + hash[1] = keyptr->secret[9]; + hash[2] = keyptr->secret[10]; + hash[3] = keyptr->secret[11]; + + return half_md4_transform(hash, keyptr->secret); +} + +#ifdef CONFIG_INET + +__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport) +{ + __u32 seq; + __u32 hash[4]; + struct keydata *keyptr = get_keyptr(); + + /* + * Pick a unique starting offset for each TCP connection endpoints + * (saddr, daddr, sport, dport). + * Note that the words are placed into the starting vector, which is + * then mixed with a partial MD4 over random data. + */ + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = ((__force u16)sport << 16) + (__force u16)dport; + hash[3] = keyptr->secret[11]; + + seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK; + seq += keyptr->count; + /* + * As close as possible to RFC 793, which + * suggests using a 250 kHz clock. + * Further reading shows this assumes 2 Mb/s networks. + * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate. + * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but + * we also need to limit the resolution so that the u32 seq + * overlaps less than one time per MSL (2 minutes). + * Choosing a clock of 64 ns period is OK. (period of 274 s) + */ + seq += ktime_to_ns(ktime_get_real()) >> 6; + + return seq; +} + +/* Generate secure starting point for ephemeral IPV4 transport port search */ +u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) +{ + struct keydata *keyptr = get_keyptr(); + u32 hash[4]; + + /* + * Pick a unique starting offset for each ephemeral port search + * (saddr, daddr, dport) and 48bits of random data. + */ + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = (__force u32)dport ^ keyptr->secret[10]; + hash[3] = keyptr->secret[11]; + + return half_md4_transform(hash, keyptr->secret); +} +EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral); + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, + __be16 dport) +{ + struct keydata *keyptr = get_keyptr(); + u32 hash[12]; + + memcpy(hash, saddr, 16); + hash[4] = (__force u32)dport; + memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); + + return twothirdsMD4Transform((const __u32 *)daddr, hash); +} +#endif + +#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE) +/* Similar to secure_tcp_sequence_number but generate a 48 bit value + * bit's 32-47 increase every key exchange + * 0-31 hash(source, dest) + */ +u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport) +{ + u64 seq; + __u32 hash[4]; + struct keydata *keyptr = get_keyptr(); + + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = ((__force u16)sport << 16) + (__force u16)dport; + hash[3] = keyptr->secret[11]; + + seq = half_md4_transform(hash, keyptr->secret); + seq |= ((u64)keyptr->count) << (32 - HASH_BITS); + + seq += ktime_to_ns(ktime_get_real()); + seq &= (1ull << 48) - 1; + + return seq; +} +EXPORT_SYMBOL(secure_dccp_sequence_number); +#endif + +#endif /* CONFIG_INET */ + + +/* + * Get a random word for internal kernel use only. Similar to urandom but + * with the goal of minimal entropy pool depletion. As a result, the random + * value is not cryptographically secure but for several uses the cost of + * depleting entropy is too high + */ +unsigned int get_random_int(void) +{ + /* + * Use IP's RNG. It suits our purpose perfectly: it re-keys itself + * every second, from the entropy pool (and thus creates a limited + * drain on it), and uses halfMD4Transform within the second. We + * also mix it with jiffies and the PID: + */ + return secure_ip_id((__force __be32)(current->pid + jiffies)); +} + +/* + * randomize_range() returns a start address such that + * + * [...... .....] + * start end + * + * a with size "len" starting at the return value is inside in the + * area defined by [start, end], but is otherwise randomized. + */ +unsigned long +randomize_range(unsigned long start, unsigned long end, unsigned long len) +{ + unsigned long range = end - len - start; + + if (end <= start + len) + return 0; + return PAGE_ALIGN(get_random_int() % range + start); +} + +#endif diff --git a/libddekit/include/ddekit/resources.h b/libddekit/include/ddekit/resources.h index dfbb1322..657295a0 100644 --- a/libddekit/include/ddekit/resources.h +++ b/libddekit/include/ddekit/resources.h @@ -9,5 +9,6 @@ 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/resources.c b/libddekit/resources.c index 212dcae7..45704378 100644 --- a/libddekit/resources.c +++ b/libddekit/resources.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -117,3 +118,8 @@ int ddekit_release_mem(ddekit_addr_t start, ddekit_addr_t count) { } return 0; } + +long ddekit_random () +{ + return random (); +} -- cgit v1.2.3