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