Imported Genode release 11.11

This commit is contained in:
Genode Labs
2011-12-22 16:19:25 +01:00
committed by Christian Helmuth
parent 6bcc9aef0e
commit da4e1feaa5
2462 changed files with 320115 additions and 3 deletions

View File

@ -0,0 +1,20 @@
/*
* \brief DDE Kit generals and initialization
* \author Christian Helmuth
* \date 2008-10-22
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
extern "C" {
#include <dde_kit/dde_kit.h>
}
extern "C" void dde_kit_init(void)
{
}

View File

@ -0,0 +1,193 @@
/*
* \brief Hardware-interrupt subsystem
* \author Christian Helmuth
* \date 2008-08-15
*
* Open issues:
*
* - IRQ thread priority
* - IRQ sharing
* - IRQ detachment
* - Could be solved by just killing driver process and reclaiming all
* resources.
* - error handling on attachment
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/env.h>
#include <base/lock.h>
#include <base/printf.h>
#include <base/thread.h>
#include <base/snprintf.h>
#include <util/avl_tree.h>
#include <irq_session/connection.h>
extern "C" {
#include <dde_kit/interrupt.h>
#include <dde_kit/thread.h>
}
#include "thread.h"
using namespace Genode;
class Irq_handler : Dde_kit::Thread, public Avl_node<Irq_handler>
{
private:
unsigned _irq_number; /* IRQ number */
Irq_connection _irq; /* IRQ connection */
char _thread_name[10];
void (*_handler)(void *); /* handler function */
void (*_init)(void *); /* thread init function */
void *_priv; /* private handler token */
bool _shared; /* true, if IRQ sharing is supported */
int _handle_irq; /* nested irq disable counter */
Lock _lock; /* synchronize access to counter */
const char * _compose_thread_name(unsigned irq)
{
snprintf(_thread_name, sizeof(_thread_name), "irq.%02x", irq);
return _thread_name;
}
public:
Irq_handler(unsigned irq, void (*handler)(void *), void *priv,
void (*init)(void *) = 0, bool shared = false)
:
Dde_kit::Thread(_compose_thread_name(irq)), _irq_number(irq),
_irq(irq), _handler(handler), _init(init), _priv(priv),
_shared(shared), _handle_irq(1)
{ start(); }
/** Enable IRQ handling */
void enable()
{
Lock::Guard lock_guard(_lock);
++_handle_irq;
}
/** Disable IRQ handling */
void disable()
{
Lock::Guard lock_guard(_lock);
--_handle_irq;
}
/** Thread entry */
void entry()
{
dde_kit_thread_adopt_myself(_thread_name);
/* call user init function before doing anything else here */
if (_init) _init(_priv);
while (1) {
_irq.wait_for_irq();
/* only call registered handler function, if IRQ is not disabled */
_lock.lock();
if (_handle_irq) _handler(_priv);
_lock.unlock();
}
}
/** AVL node comparison */
bool higher(Irq_handler *irq_handler) {
return (_irq_number < irq_handler->_irq_number); }
/** AVL node lookup */
Irq_handler *lookup(unsigned irq_number)
{
if (irq_number == _irq_number) return this;
Irq_handler *h = child(_irq_number < irq_number);
return h ? h->lookup(irq_number) : 0;
}
};
class Irq_handler_database : public Avl_tree<Irq_handler>
{
private:
Lock _lock;
public:
Irq_handler *lookup(unsigned irq_number)
{
Lock::Guard lock_guard(_lock);
return first() ? first()->lookup(irq_number) : 0;
}
void insert(Irq_handler *h)
{
Lock::Guard lock_guard(_lock);
Avl_tree<Irq_handler>::insert(h);
}
void remove(Irq_handler *h)
{
Lock::Guard lock_guard(_lock);
Avl_tree<Irq_handler>::remove(h);
}
};
static Irq_handler_database *irq_handlers()
{
static Irq_handler_database _irq_handlers;
return &_irq_handlers;
}
extern "C" int dde_kit_interrupt_attach(int irq, int shared,
void(*thread_init)(void *),
void(*handler)(void *), void *priv)
{
Irq_handler *h;
try {
h = new (env()->heap()) Irq_handler(irq, handler, priv, thread_init);
} catch (...) {
PERR("allocation failed (size=%zd)", sizeof(*h));
return -1;
}
irq_handlers()->insert(h);
return 0;
}
extern "C" void dde_kit_interrupt_detach(int irq) {
PERR("not implemented yet"); }
extern "C" void dde_kit_interrupt_disable(int irq)
{
Irq_handler *h = irq_handlers()->lookup(irq);
if (h) h->disable();
}
extern "C" void dde_kit_interrupt_enable(int irq)
{
Irq_handler *h = irq_handlers()->lookup(irq);
if (h) h->enable();
}

View File

@ -0,0 +1,67 @@
/*
* \brief Locks (i.e., mutex)
* \author Christian Helmuth
* \date 2008-08-15
*
* Open issues:
*
* - What about slabs for locks?
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/env.h>
#include <base/lock.h>
#include <base/printf.h>
extern "C" {
#include <dde_kit/lock.h>
}
struct dde_kit_lock { };
extern "C" void dde_kit_lock_init(struct dde_kit_lock **out_lock)
{
try {
*out_lock = reinterpret_cast<struct dde_kit_lock *>
(new (Genode::env()->heap()) Genode::Lock());
} catch (...) {
PERR("lock creation failed");
}
}
extern "C" void dde_kit_lock_deinit(struct dde_kit_lock *lock)
{
try {
destroy(Genode::env()->heap(), reinterpret_cast<Genode::Lock *>(lock));
} catch (...) { }
}
extern "C" void dde_kit_lock_lock(struct dde_kit_lock *lock)
{
reinterpret_cast<Genode::Lock *>(lock)->lock();
}
extern "C" int dde_kit_lock_try_lock(struct dde_kit_lock *lock)
{
PERR("not implemented - will potentially block");
reinterpret_cast<Genode::Lock *>(lock)->lock();
/* success */
return 0;
}
extern "C" void dde_kit_lock_unlock(struct dde_kit_lock *lock)
{
reinterpret_cast<Genode::Lock *>(lock)->unlock();
}

View File

@ -0,0 +1,301 @@
/*
* \brief Memory subsystem
* \author Christian Helmuth
* \date 2008-08-15
*
* Open issues:
*
* - Rethink file split up
* - What about slabs for large malloc blocks?
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/env.h>
#include <base/lock.h>
#include <base/printf.h>
#include <base/slab.h>
#include <util/avl_tree.h>
#include <util/misc_math.h>
#include <dataspace/client.h>
#include <os/attached_ram_dataspace.h>
extern "C" {
#include <dde_kit/memory.h>
#include <dde_kit/pgtab.h>
}
using namespace Genode;
/*****************************
** Backing store allocator **
*****************************/
/*
* The backing store allocator allocates RAM dataspaces and maintains virtual
* page-table entries.
*/
class Backing_store_allocator : public Allocator
{
private:
class Block : public Avl_node<Block>
{
private:
Attached_ram_dataspace *_ram_ds;
public:
Block(Attached_ram_dataspace *ram_ds) : _ram_ds(ram_ds) { }
Attached_ram_dataspace *ram_ds() const { return _ram_ds; }
/* AVL node comparison */
bool higher(Block *b) {
return _ram_ds->local_addr<void>() < b->_ram_ds->local_addr<void>(); }
/* AVL node lookup */
Block *lookup(void *virt)
{
if (virt == _ram_ds->local_addr<void>()) return this;
Block *b = child(_ram_ds->local_addr<void>() < virt);
return b ? b->lookup(virt) : 0;
}
};
Avl_tree<Block> _map; /* backing store block map */
size_t _consumed; /* allocated memory size */
Lock _lock; /* synchronize access to allocator */
public:
Backing_store_allocator() { }
virtual ~Backing_store_allocator() { }
/***************
** Allocator **
***************/
bool alloc(size_t size, void **out_addr)
{
Lock::Guard lock_guard(_lock);
Attached_ram_dataspace *ram_ds;
/* alloc and attach RAM dataspace */
try {
ram_ds = new (env()->heap()) Attached_ram_dataspace(env()->ram_session(), size);
} catch (...) {
PERR("RAM allocation failed (size=%zx)", size);
return false;
}
/* setup virt->phys and phys->virt mappings */
void *virt = ram_ds->local_addr<void>();
addr_t phys = Dataspace_client(ram_ds->cap()).phys_addr();
dde_kit_pgtab_set_region_with_size(virt, phys, size);
/* store allocation in our map */
Block *b = new (env()->heap()) Block(ram_ds);
/* cleanup on error */
if (!b) {
dde_kit_pgtab_clear_region(virt);
destroy(env()->heap(), ram_ds);
return false;
}
_map.insert(b);
_consumed += size;
*out_addr = virt;
return true;
}
void free(void *virt, size_t size)
{
Lock::Guard lock_guard(_lock);
/* lookup address */
Block *b = _map.first() ? _map.first()->lookup(virt) : 0;
if (!b) return;
Attached_ram_dataspace *ram_ds = b->ram_ds();
/*
* We support freeing of the whole block only.
*/
if (size && (size != dde_kit_pgtab_get_size(virt)))
PERR("Cannot split RAM allocations - the whole block is free'd.");
/* remove allocation from our map */
_map.remove(b);
/* delete virt->phys and phys->virt mappings */
dde_kit_pgtab_clear_region(virt);
/* detach and free RAM dataspace */
destroy(env()->heap(), ram_ds);
/* free meta data */
destroy(env()->heap(), b);
}
size_t consumed() { return _consumed; }
size_t overhead(size_t size) { return 0; }
};
/**
* Get backing store allocator
*
* \return reference to static backing store object
*/
static Backing_store_allocator * backing_store_allocator()
{
static Backing_store_allocator _backing_store_allocator;
return &_backing_store_allocator;
}
/*******************
** Slab facility **
*******************/
struct dde_kit_slab : public Slab
{
private:
void *_data;
size_t _object_size;
/*
* Each slab in the slab cache contains about 8 objects as proposed in
* the paper by Bonwick and block sizes are multiples of page size.
*/
size_t _calculate_block_size(size_t object_size)
{
size_t block_size = 8 * (object_size + sizeof(Slab_entry)) + sizeof(Slab_block);
return align_addr(block_size, DDE_KIT_PAGE_SHIFT);
}
public:
dde_kit_slab(size_t object_size)
:
Slab(object_size, _calculate_block_size(object_size), 0, backing_store_allocator()),
_object_size(object_size) { }
inline void *alloc()
{
void *result;
return (Slab::alloc(_object_size, &result) ? result : 0);
}
inline void *data() const { return _data; }
inline void data(void *data) { _data = data; }
};
extern "C" void dde_kit_slab_set_data(struct dde_kit_slab * slab, void *data) {
slab->data(data); }
extern "C" void *dde_kit_slab_get_data(struct dde_kit_slab * slab) {
return slab->data(); }
extern "C" void *dde_kit_slab_alloc(struct dde_kit_slab * slab) {
return slab->alloc(); }
extern "C" void dde_kit_slab_free(struct dde_kit_slab * slab, void *objp) {
slab->free(objp); }
extern "C" void dde_kit_slab_destroy(struct dde_kit_slab * slab) {
destroy(env()->heap(), slab); }
extern "C" struct dde_kit_slab * dde_kit_slab_init(unsigned size)
{
dde_kit_slab *slab_cache;
try {
slab_cache = new (env()->heap()) dde_kit_slab(size);
} catch (...) {
PERR("allocation failed (size=%zd)", sizeof(*slab_cache));
return 0;
}
return slab_cache;
}
/**********************************
** Large-block memory allocator **
**********************************/
extern "C" void *dde_kit_large_malloc(dde_kit_size_t size)
{
void *virt;
if (!backing_store_allocator()->alloc(size, &virt))
return 0;
return virt;
}
extern "C" void dde_kit_large_free(void *virt) {
backing_store_allocator()->free(virt, 0);
}
/*****************************
** Simple memory allocator **
*****************************/
extern "C" void *dde_kit_simple_malloc(dde_kit_size_t size)
{
/*
* We store the size of the allocation at the very
* beginning of the allocated block and return
* the subsequent address. This way, we can retrieve
* the size information when freeing the block.
*/
size_t real_size = size + sizeof(size_t);
size_t *addr;
try {
addr = (size_t *)env()->heap()->alloc(real_size);
} catch (...) {
return 0;
}
*addr = real_size;
return addr + 1;
}
extern "C" void dde_kit_simple_free(void *p)
{
if (!p) return;
size_t *addr = ((size_t *)p) - 1;
env()->heap()->free(addr, *addr);
}

View File

@ -0,0 +1,45 @@
/*
* \brief Debugging support
* \author Christian Helmuth
* \date 2008-08-15
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/printf.h>
#include <base/sleep.h>
extern "C" {
#include <dde_kit/panic.h>
}
extern "C" void dde_kit_panic(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
Genode::vprintf(fmt, va);
va_end(va);
Genode::printf("\n");
/* XXX original implementation enters a kernel debugger here */
Genode::sleep_forever();
}
extern "C" void dde_kit_debug(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
Genode::vprintf(fmt, va);
va_end(va);
Genode::printf("\n");
/* XXX original implementation enters a kernel debugger here */
Genode::sleep_forever();
}

151
os/src/lib/dde_kit/pci.cc Normal file
View File

@ -0,0 +1,151 @@
/*
* \brief PCI bus access
* \author Christian Helmuth
* \date 2008-10-22
*
* We provide a virtual PCI bus hierarchy in pci_tree.cc:
*
* - Grab all accessible devices at pci_drv and populate virtual bus hierarchy.
* (This also works if parents/device managers limit device access in the
* future.)
* - DDE kit C interface in pci.cc
* - Read/write config space
* - Convenience functions
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/printf.h>
extern "C" {
#include <dde_kit/pci.h>
}
#include "pci_tree.h"
static const bool verbose = false;
static Dde_kit::Pci_tree *pci_tree()
{
static Dde_kit::Pci_tree _pci_tree;
return &_pci_tree;
}
/********************************
** Configuration space access **
********************************/
extern "C" void dde_kit_pci_readb(int bus, int dev, int fun, int pos, dde_kit_uint8_t *val)
{
try {
*val = pci_tree()->config_read(bus, dev, fun, pos, Pci::Device::ACCESS_8BIT) & 0xff;
} catch (...) {
if (verbose)
PWRN("PCI device %02x:%02x.%x not found", bus, dev, fun);
*val = ~0;
}
}
extern "C" void dde_kit_pci_readw(int bus, int dev, int fun, int pos, dde_kit_uint16_t *val)
{
try {
*val = pci_tree()->config_read(bus, dev, fun, pos, Pci::Device::ACCESS_16BIT) & 0xffff;
} catch (...) {
if (verbose)
PWRN("PCI device %02x:%02x.%x not found", bus, dev, fun);
*val = ~0;
}
}
extern "C" void dde_kit_pci_readl(int bus, int dev, int fun, int pos, dde_kit_uint32_t *val)
{
try {
*val = pci_tree()->config_read(bus, dev, fun, pos, Pci::Device::ACCESS_32BIT);
} catch (...) {
if (verbose)
PWRN("PCI device %02x:%02x.%x not found", bus, dev, fun);
*val = ~0;
}
}
extern "C" void dde_kit_pci_writeb(int bus, int dev, int fun, int pos, dde_kit_uint8_t val)
{
try {
pci_tree()->config_write(bus, dev, fun, pos, val, Pci::Device::ACCESS_8BIT);
} catch (...) {
if (verbose)
PWRN("PCI device %02x:%02x.%x not found", bus, dev, fun);
}
}
extern "C" void dde_kit_pci_writew(int bus, int dev, int fun, int pos, dde_kit_uint16_t val)
{
try {
pci_tree()->config_write(bus, dev, fun, pos, val, Pci::Device::ACCESS_16BIT);
} catch (...) {
if (verbose)
PWRN("PCI device %02x:%02x.%x not found", bus, dev, fun);
}
}
extern "C" void dde_kit_pci_writel(int bus, int dev, int fun, int pos, dde_kit_uint32_t val)
{
try {
pci_tree()->config_write(bus, dev, fun, pos, val, Pci::Device::ACCESS_32BIT);
} catch (...) {
if (verbose)
PWRN("PCI device %02x:%02x.%x not found", bus, dev, fun);
}
}
/***************************
** Convenience functions **
***************************/
extern "C" int dde_kit_pci_first_device(int *bus, int *dev, int *fun)
{
try {
pci_tree()->first_device(bus, dev, fun);
return 0;
} catch (...) {
return -1;
}
}
extern "C" int dde_kit_pci_next_device(int *bus, int *dev, int *fun)
{
try {
pci_tree()->next_device(bus, dev, fun);
return 0;
} catch (...) {
return -1;
}
}
/********************
** Initialization **
********************/
extern "C" void dde_kit_pci_init(void)
{
try {
pci_tree();
} catch (...) {
PERR("PCI initialization failed");
}
}

View File

@ -0,0 +1,74 @@
/*
* \brief Virtual PCI bus tree for DDE kit
* \author Christian Helmuth
* \date 2008-10-22
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include "pci_tree.h"
using namespace Dde_kit;
static const bool verbose = false;
static const bool verbose_access = false;
/****************
** PCI device **
****************/
uint32_t Pci_device::config_read(unsigned char address, Pci::Device::Access_size size)
{
uint32_t result = _device.config_read(address, size);
if (verbose_access)
PDBG("PCI read cfg (%d) %x of %02x:%02x.%x -- %x",
size, address, bus(), dev(), fun(), result);
return result;
}
void Pci_device::config_write(unsigned char address, uint32_t val,
Pci::Device::Access_size size)
{
_device.config_write(address, val, size);
if (verbose_access)
PDBG("PCI write cfg (%d) %x (%x) of %02x:%02x.%x",
size, address, val, bus(), dev(), fun());
}
/*************
** PCI bus **
*************/
Pci_tree::Pci_tree()
{
/*
* Iterate through all accessible devices and populate virtual
* PCI bus tree.
*/
Pci::Device_capability prev_device_cap,
device_cap = _pci_drv.first_device();
while (device_cap.valid()) {
Pci_device *device = new (env()->heap())
Pci_device(device_cap);
_devices.insert(device);
prev_device_cap = device_cap;
device_cap = _pci_drv.next_device(prev_device_cap);
}
if (verbose)
_show_devices();
}

View File

@ -0,0 +1,247 @@
/*
* \brief Virtual PCI bus tree for DDE kit
* \author Christian Helmuth
* \date 2008-10-22
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _PCI_TREE_H_
#define _PCI_TREE_H_
#include <base/stdint.h>
#include <base/printf.h>
#include <base/lock.h>
#include <util/avl_tree.h>
#include <pci_session/connection.h>
#include <pci_device/client.h>
namespace Dde_kit {
using namespace Genode;
class Pci_device : public Avl_node<Pci_device>
{
public:
static inline unsigned short knit_bdf(int bus, int dev, int fun)
{
return ((bus & 0xff) << 8)
| ((dev & 0x1f) << 3)
| (fun & 0x07);
}
private:
Pci::Device_client _device;
unsigned short _bdf; /* bus:device:function */
public:
Pci_device(Pci::Device_capability device_cap) : _device(device_cap)
{
unsigned char bus = ~0, dev = ~0, fun = ~0;
_device.bus_address(&bus, &dev, &fun);
_bdf = knit_bdf(bus, dev, fun);
}
/***************
** Accessors **
***************/
unsigned short bdf() const { return _bdf; }
unsigned char bus() const { return (_bdf >> 8) & 0xff; }
unsigned char dev() const { return (_bdf >> 3) & 0x1f; }
unsigned char fun() const { return _bdf & 0x07; }
/********************************
** Configuration space access **
********************************/
uint32_t config_read(unsigned char address, Pci::Device::Access_size size);
void config_write(unsigned char address, uint32_t val,
Pci::Device::Access_size size);
/** AVL node comparison */
bool higher(Pci_device *device) {
return (_bdf < device->_bdf); }
Pci_device *next(Pci_device *root, Side direction)
{
/*
* The predecessor of a node is the right-most node of the left
* subtree or the parent right after the first "left turn" up to
* the root of the tree. Symmetrically, the successor of a node is
* the left-most node of the right subtree or the parent right
* after the first "right turn" up to the root of the tree.
*/
if (child(direction)) {
Pci_device *n = child(direction);
while (true) {
if (!n->child(!direction))
return n;
else
n = n->child(!direction);
}
} else {
Pci_device *n = this;
for (Pci_device *parent = static_cast<Pci_device *>(n->_parent);
n != root;
n = parent, parent = static_cast<Pci_device *>(n->_parent)) {
if (n == parent->child(!direction))
return parent;
}
return 0;
}
}
void show()
{
if (child(LEFT)) child(LEFT)->show();
unsigned char ht = config_read(0x0e, Pci::Device::ACCESS_8BIT) & 0xff;
PINF("%02x:%02x.%x %04x:%04x (%x) ht=%02x",
bus(), dev(), fun(),
_device.vendor_id(), _device.device_id(), _device.base_class(), ht);
if (child(RIGHT)) child(RIGHT)->show();
}
};
class Pci_tree
{
public:
class Not_found : public Exception { };
private:
int _current_dev_num;
Pci::Connection _pci_drv;
Avl_tree<Pci_device> _devices;
Lock _lock;
/* Lookup device for given BDF */
Pci_device *_lookup(unsigned short bdf)
{
if (!_devices.first())
throw Not_found();
Pci_device *d = _devices.first();
do {
if (bdf == d->bdf())
return d;
if (bdf < d->bdf())
d = d->child(Pci_device::LEFT);
else
d = d->child(Pci_device::RIGHT);
} while (d);
throw Not_found();
}
/** Find lowest BDF */
void _first_bdf(int *bus, int *dev, int *fun)
{
if (!_devices.first())
throw Not_found();
Pci_device *first, *prev, *root;
first = prev = root = _devices.first();
do {
first = prev;
prev = prev->next(root, Pci_device::LEFT);
} while (prev);
*bus = first->bus();
*dev = first->dev();
*fun = first->fun();
}
/** Find next BDF */
void _next_bdf(Pci_device *prev, int *bus, int *dev, int *fun)
{
if (!_devices.first())
throw Not_found();
Pci_device *next = prev->next(_devices.first(), Pci_device::RIGHT);
if (!next)
throw Not_found();
*bus = next->bus();
*dev = next->dev();
*fun = next->fun();
}
void _show_devices()
{
if (_devices.first())
_devices.first()->show();
}
public:
Pci_tree();
uint32_t config_read(int bus, int dev, int fun, unsigned char address,
Pci::Device::Access_size size)
{
Lock::Guard lock_guard(_lock);
unsigned short bdf = Pci_device::knit_bdf(bus, dev, fun);
return _lookup(bdf)->config_read(address, size);
}
void config_write(int bus, int dev, int fun, unsigned char address,
uint32_t val, Pci::Device::Access_size size)
{
Lock::Guard lock_guard(_lock);
unsigned short bdf = Pci_device::knit_bdf(bus, dev, fun);
_lookup(bdf)->config_write(address, val, size);
}
/**
* Lookup first device
*/
void first_device(int *bus, int *dev, int *fun)
{
Lock::Guard lock_guard(_lock);
_first_bdf(bus, dev, fun);
}
/**
* Lookup next device
*/
void next_device(int *bus, int *dev, int *fun)
{
Lock::Guard lock_guard(_lock);
Pci_device *d = _lookup(Pci_device::knit_bdf(*bus, *dev, *fun));
_next_bdf(d, bus, dev, fun);
}
};
}
#endif /* _PCI_TREE_H_ */

194
os/src/lib/dde_kit/pgtab.cc Normal file
View File

@ -0,0 +1,194 @@
/*
* \brief Virtual page-table facility
* \author Christian Helmuth
* \date 2008-08-15
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/stdint.h>
#include <base/env.h>
#include <base/sync_allocator.h>
#include <base/allocator_avl.h>
#include <base/printf.h>
extern "C" {
#include <dde_kit/pgtab.h>
}
using namespace Genode;
class Mem_region
{
private:
addr_t _base; /* region base address */
size_t _size; /* region size */
addr_t _mapped_base; /* base address in other address space */
public:
Mem_region() : _base(0), _size(0), _mapped_base(0) { }
Mem_region(addr_t base, size_t size, addr_t mapped_base)
: _base(base), _size(size), _mapped_base(mapped_base) { }
/***************
** Accessors **
***************/
addr_t base() const { return _base; }
size_t size() const { return _size; }
addr_t mapped_base() const { return _mapped_base; }
};
typedef Allocator_avl_tpl<Mem_region> Mem_region_allocator;
class Mem_map : public Synchronized_range_allocator<Mem_region_allocator>
{
public:
Mem_map()
: Synchronized_range_allocator<Mem_region_allocator>(env()->heap()) {
add_range(0, ~0); }
/***********************************
** Wrapped Allocator_avl methods **
***********************************/
/**
* Assign custom meta data to block at specified address
*/
void metadata(void *addr, Mem_region region)
{
Lock::Guard lock_guard(*lock());
raw()->metadata(addr, region);
}
/**
* Return meta data that was attached to block at specified address
*/
Mem_region * metadata(void *addr)
{
Lock::Guard lock_guard(*lock());
return raw()->metadata(addr);
}
};
static Mem_map * phys_to_virt_map()
{
static Mem_map _phys_to_virt_map;
return &_phys_to_virt_map;
}
static Mem_map * virt_to_phys_map()
{
static Mem_map _virt_to_phys_map;
return &_virt_to_phys_map;
}
extern "C" void dde_kit_pgtab_set_region(void *virt, dde_kit_addr_t phys, unsigned pages)
{
dde_kit_pgtab_set_region_with_size(virt, phys, pages << DDE_KIT_PAGE_SHIFT);
}
extern "C" void dde_kit_pgtab_set_region_with_size(void *virt, dde_kit_addr_t phys,
dde_kit_size_t size)
{
Mem_map *map;
Mem_region region;
/* add region to virtual memory map */
map = virt_to_phys_map();
region = Mem_region(reinterpret_cast<addr_t>(virt), size, phys);
if (map->alloc_addr(size, reinterpret_cast<addr_t>(virt)) == Range_allocator::ALLOC_OK)
map->metadata(virt, region);
else
PWRN("virt->phys mapping for [%lx,%lx) failed",
reinterpret_cast<addr_t>(virt), reinterpret_cast<addr_t>(virt) + size);
/* add region to physical memory map for reverse lookup */
map = phys_to_virt_map();
region = Mem_region(phys, size, reinterpret_cast<addr_t>(virt));
if (map->alloc_addr(size, phys) == Range_allocator::ALLOC_OK)
map->metadata(reinterpret_cast<void *>(phys), region);
else
PWRN("phys->virt mapping for [%lx,%lx) failed", phys, phys + size);
}
extern "C" void dde_kit_pgtab_clear_region(void *virt)
{
Mem_region *region =virt_to_phys_map()->metadata(virt);
if (!region) {
PWRN("no virt->phys mapping @ %p", virt);
return;
}
void *phys = reinterpret_cast<void *>(region->mapped_base());
/* remove region from both maps */
virt_to_phys_map()->free(virt);
phys_to_virt_map()->free(phys);
}
extern "C" dde_kit_addr_t dde_kit_pgtab_get_physaddr(void *virt)
{
addr_t phys;
Mem_region *region = virt_to_phys_map()->metadata(virt);
if (!region) {
PWRN("no virt->phys mapping @ %p", virt);
return 0;
}
phys = reinterpret_cast<addr_t>(virt) - region->base() + region->mapped_base();
return phys;
}
extern "C" dde_kit_addr_t dde_kit_pgtab_get_virtaddr(dde_kit_addr_t phys)
{
addr_t virt;
Mem_region *region = phys_to_virt_map()->metadata(reinterpret_cast<void *>(phys));
if (!region) {
PWRN("no phys->virt mapping @ %p", reinterpret_cast<void *>(phys));
return 0;
}
virt = phys - region->base() + region->mapped_base();
return virt;
}
extern "C" dde_kit_size_t dde_kit_pgtab_get_size(void *virt)
{
Mem_region *region =virt_to_phys_map()->metadata(virt);
if (!region) {
PWRN("no virt->phys mapping @ %p", virt);
return 0;
}
return region->size();
}

View File

@ -0,0 +1,40 @@
/*
* \brief Formatted output
* \author Christian Helmuth
* \date 2008-08-15
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/printf.h>
extern "C" {
#include <dde_kit/printf.h>
}
extern "C" void dde_kit_print(const char *msg)
{
Genode::printf(msg);
}
extern "C" void dde_kit_printf(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
Genode::vprintf(fmt, va);
va_end(va);
}
extern "C" void dde_kit_vprintf(const char *fmt, va_list va)
{
Genode::vprintf(fmt, va);
}

View File

@ -0,0 +1,339 @@
/*
* \brief Hardware-resource access
* \author Christian Helmuth
* \date 2008-10-21
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/lock.h>
#include <base/stdint.h>
#include <util/avl_tree.h>
#include <io_port_session/connection.h>
#include <io_mem_session/connection.h>
#include <dataspace/client.h>
extern "C" {
#include <dde_kit/resources.h>
#include <dde_kit/pgtab.h>
}
using namespace Genode;
static const bool verbose = false;
class Range : public Avl_node<Range>
{
public:
class Not_found : public Exception { };
class Overlap : public Exception { };
class Resource_not_accessible : public Exception { };
private:
addr_t _base;
size_t _size;
public:
Range(addr_t base, size_t size) : _base(base), _size(size) { }
/** AVL node comparison */
bool higher(Range *range) {
return (_base + _size <= range->_base); }
/** AVL node lookup */
Range *lookup(addr_t addr, size_t size)
{
Range *r = this;
do {
if (addr >= r->_base) {
if (addr + size <= r->_base + r->_size)
return r;
else if (addr < r->_base + r->_size)
throw Overlap();
}
if (addr < r->_base)
r = r->child(LEFT);
else
r = r->child(RIGHT);
} while (r);
throw Not_found();
}
/**
* Log ranges of node and all children
*/
void log_ranges()
{
if (child(LEFT))
child(LEFT)->log_ranges();
PLOG(" [%08lx,%08lx)", _base, _base + _size);
if (child(RIGHT))
child(RIGHT)->log_ranges();
}
addr_t base() const { return _base; }
size_t size() const { return _size; }
};
template <typename TYPE>
class Range_database : Avl_tree<Range>
{
private:
Lock _lock;
void _log_ranges(const char *op, addr_t b, size_t s)
{
PLOG("Range_db %p: %s [%08lx,%08lx)", this, op, b, b + s);
if (!first())
PLOG(" <no ranges>");
else
first()->log_ranges();
}
public:
TYPE *lookup(addr_t addr, size_t size)
{
Lock::Guard lock_guard(_lock);
if (!first()) throw Range::Not_found();
return static_cast<TYPE *>(first()->lookup(addr, size));
}
void insert(Range *range)
{
Lock::Guard lock_guard(_lock);
Avl_tree<Range>::insert(range);
if (verbose)
_log_ranges("INSERT", range->base(), range->size());
}
void remove(Range *range)
{
Lock::Guard lock_guard(_lock);
Avl_tree<Range>::remove(range);
if (verbose)
_log_ranges("REMOVE", range->base(), range->size());
}
};
/***************
** I/O ports **
***************/
class Port_range;
static Range_database<Port_range> *ports()
{
static Range_database<Port_range> _ports;
return &_ports;
}
class Port_range : public Range, public Io_port_connection
{
public:
Port_range(addr_t base, size_t size)
: Range(base, size), Io_port_connection(base, size) {
ports()->insert(this); }
~Port_range() { ports()->remove(this); }
};
extern "C" int dde_kit_request_io(dde_kit_addr_t addr, dde_kit_size_t size)
{
try {
new (env()->heap()) Port_range(addr, size);
return 0;
} catch (...) {
return -1;
}
}
extern "C" int dde_kit_release_io(dde_kit_addr_t addr, dde_kit_size_t size)
{
try {
destroy(env()->heap(), ports()->lookup(addr, size));
return 0;
} catch (...) {
return -1;
}
}
extern "C" unsigned char dde_kit_inb(dde_kit_addr_t port)
{
try {
return ports()->lookup(port, 1)->inb(port);
} catch (...) {
return 0;
}
}
extern "C" unsigned short dde_kit_inw(dde_kit_addr_t port)
{
try {
return ports()->lookup(port, 2)->inw(port);
} catch (...) {
return 0;
}
}
extern "C" unsigned long dde_kit_inl(dde_kit_addr_t port)
{
try {
return ports()->lookup(port, 4)->inl(port);
} catch (...) {
return 0;
}
}
extern "C" void dde_kit_outb(dde_kit_addr_t port, unsigned char val)
{
try {
ports()->lookup(port, 1)->outb(port, val);
} catch (...) { }
}
extern "C" void dde_kit_outw(dde_kit_addr_t port, unsigned short val)
{
try {
ports()->lookup(port, 2)->outw(port, val);
} catch (...) { }
}
extern "C" void dde_kit_outl(dde_kit_addr_t port, unsigned long val)
{
try {
ports()->lookup(port, 4)->outl(port, val);
} catch (...) { }
}
/******************
** MMIO regions **
******************/
class Mem_range;
static Range_database<Mem_range> *mem_db()
{
static Range_database<Mem_range> _mem_db;
return &_mem_db;
}
class Mem_range : public Range, public Io_mem_connection
{
private:
bool _wc;
Io_mem_dataspace_capability _ds;
addr_t _vaddr;
public:
Mem_range(addr_t base, size_t size, bool wc)
:
Range(base, size), Io_mem_connection(base, size, wc),
_wc(wc), _ds(dataspace())
{
if (!_ds.valid()) throw Resource_not_accessible();
_vaddr = env()->rm_session()->attach(_ds);
_vaddr |= base & 0xfff;
dde_kit_pgtab_set_region_with_size((void *)_vaddr, base, size);
mem_db()->insert(this);
}
~Mem_range()
{
mem_db()->remove(this);
dde_kit_pgtab_clear_region((void *)_vaddr);
}
addr_t vaddr() const { return _vaddr; }
bool wc() const { return _wc; }
};
extern "C" int dde_kit_request_mem(dde_kit_addr_t addr, dde_kit_size_t size,
int wc, dde_kit_addr_t *vaddr)
{
/*
* We check if a resource comprising the requested region was allocated
* before (with the same access type, i.e., wc flag) and then return the
* mapping address. In case of overlapping requests, there's nothing else
* for it but to return an error.
*/
try {
Mem_range *r = mem_db()->lookup(addr, size);
if (!!wc != r->wc()) {
PERR("I/O memory access type mismatch");
return -1;
}
*vaddr = r->vaddr() + (addr - r->base());
return 0;
} catch (Mem_range::Overlap) {
PERR("overlapping I/O memory region requested");
return -1;
} catch (Mem_range::Not_found) { }
/* request resource if no previous allocation was found */
try {
*vaddr = (new (env()->heap()) Mem_range(addr, size, !!wc))->vaddr();
return 0;
} catch (...) {
return -1;
}
}
extern "C" int dde_kit_release_mem(dde_kit_addr_t addr, dde_kit_size_t size)
{
try {
destroy(env()->heap(), mem_db()->lookup(addr, size));
return 0;
} catch (...) {
return -1;
}
}

View File

@ -0,0 +1,66 @@
/*
* \brief Semaphores
* \author Christian Helmuth
* \date 2008-09-15
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/env.h>
#include <base/printf.h>
#include <base/semaphore.h>
extern "C" {
#include <dde_kit/semaphore.h>
}
using namespace Genode;
struct dde_kit_sem : public Semaphore
{
public:
dde_kit_sem(int value) : Semaphore(value) { }
};
extern "C" void dde_kit_sem_down(dde_kit_sem_t *sem) {
sem->down(); }
extern "C" int dde_kit_sem_down_try(dde_kit_sem_t *sem)
{
PERR("not implemented - will potentially block");
sem->down();
/* success */
return 0;
}
extern "C" void dde_kit_sem_up(dde_kit_sem_t *sem) { sem->up(); }
extern "C" dde_kit_sem_t *dde_kit_sem_init(int value)
{
dde_kit_sem *s;
try {
s = new (env()->heap()) dde_kit_sem(value);
} catch (...) {
PERR("allocation failed (size=%zd)", sizeof(*s));
return 0;
}
return s;
}
extern "C" void dde_kit_sem_deinit(dde_kit_sem_t *sem) {
destroy(env()->heap(), sem); }

View File

@ -0,0 +1,308 @@
/*
* \brief Thread facility
* \author Christian Helmuth
* \date 2008-10-20
*
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/env.h>
#include <base/sleep.h>
#include <base/lock.h>
#include <base/printf.h>
extern "C" {
#include <dde_kit/thread.h>
#include <dde_kit/timer.h>
}
#include "thread.h"
using namespace Genode;
/***********+**************
** Thread info database **
**************************/
class Thread_info_database : public Avl_tree<Dde_kit::Thread_info>
{
private:
Lock _lock;
public:
Dde_kit::Thread_info *lookup(Thread_base *thread_base)
{
Lock::Guard lock_guard(_lock);
if (!first()) throw Dde_kit::Thread_info::Not_found();
return first()->lookup(thread_base);
}
void insert(Dde_kit::Thread_info *info)
{
Lock::Guard lock_guard(_lock);
Avl_tree<Dde_kit::Thread_info>::insert(info);
}
void remove(Dde_kit::Thread_info *info)
{
Lock::Guard lock_guard(_lock);
Avl_tree<Dde_kit::Thread_info>::remove(info);
}
};
static Thread_info_database *threads()
{
static Thread_info_database _threads;
return &_threads;
}
/********************************
** Generic thread information **
********************************/
unsigned Dde_kit::Thread_info::_id_counter = 0x1000;
bool Dde_kit::Thread_info::higher(Thread_info *info)
{
return (info->_thread_base >= _thread_base);
}
Dde_kit::Thread_info *Dde_kit::Thread_info::lookup(Thread_base *thread_base)
{
Dde_kit::Thread_info *info = this;
do {
if (thread_base == info->_thread_base) return info;
if (thread_base < info->_thread_base)
info = info->child(LEFT);
else
info = info->child(RIGHT);
} while (info);
/* thread not in AVL tree */
throw Not_found();
}
Dde_kit::Thread_info::Thread_info(Thread_base *thread_base, const char *name)
: _thread_base(thread_base), _name(name), _id(_id_counter++)
{ }
Dde_kit::Thread_info::~Thread_info()
{ }
/********************
** DDE Kit thread **
********************/
static Dde_kit::Thread_info *adopt_thread(Thread_base *thread, const char *name)
{
Dde_kit::Thread_info *info = 0;
try {
info = new (env()->heap()) Dde_kit::Thread_info(thread, name);
threads()->insert(info);
} catch (...) {
PERR("thread adoption failed");
return 0;
}
return info;
}
struct dde_kit_thread : public Dde_kit::Thread_info
{
/**
* Dummy constructor
*
* This constructor is never executed because we only use pointers to
* 'dde_kit_thread'. Even though, this constructor is never used, gcc-3.4
* (e.g., used for OKL4v2) would report an error if it did not exist.
*/
dde_kit_thread() : Dde_kit::Thread_info(0, 0) { }
};
class _Thread : public Dde_kit::Thread
{
private:
void (*_thread_fn)(void *);
void *_thread_arg;
Dde_kit::Thread_info *_thread_info;
public:
_Thread(const char *name, void (*thread_fn)(void *), void *thread_arg)
:
Dde_kit::Thread(name),
_thread_fn(thread_fn), _thread_arg(thread_arg),
_thread_info(adopt_thread(this, name))
{ start(); }
void entry() { _thread_fn(_thread_arg); }
Dde_kit::Thread_info *thread_info() { return _thread_info; }
};
extern "C" struct dde_kit_thread *dde_kit_thread_create(void (*fun)(void *),
void *arg, const char *name)
{
_Thread *thread;
try {
thread = new (env()->heap()) _Thread(name, fun, arg);
} catch (...) {
PERR("thread creation failed");
return 0;
}
return static_cast<struct dde_kit_thread *>(thread->thread_info());
}
extern "C" struct dde_kit_thread *dde_kit_thread_adopt_myself(const char *name)
{
try {
return static_cast<dde_kit_thread *>(adopt_thread(Thread_base::myself(), name));
} catch (...) {
PERR("thread adoption failed");
return 0;
}
}
extern "C" struct dde_kit_thread *dde_kit_thread_myself()
{
try {
return static_cast<struct dde_kit_thread *>
(threads()->lookup(Thread_base::myself()));
} catch (...) {
return 0;
}
}
extern "C" void * dde_kit_thread_get_data(struct dde_kit_thread *thread) {
return static_cast<Dde_kit::Thread_info *>(thread)->data(); }
extern "C" void * dde_kit_thread_get_my_data(void)
{
try {
return (threads()->lookup(Thread_base::myself()))->data();
} catch (...) {
PERR("current thread not in database");
return 0;
}
}
extern "C" void dde_kit_thread_set_data(struct dde_kit_thread *thread, void *data) {
reinterpret_cast<Dde_kit::Thread_info *>(thread)->data(data); }
extern "C" void dde_kit_thread_set_my_data(void *data)
{
try {
(threads()->lookup(Thread_base::myself()))->data(data);
} catch (...) {
PERR("current thread not in database");
}
}
extern "C" void dde_kit_thread_exit(void)
{
PERR("not implemented yet");
sleep_forever();
}
extern "C" const char *dde_kit_thread_get_name(struct dde_kit_thread *thread) {
return reinterpret_cast<Dde_kit::Thread_info *>(thread)->name(); }
extern "C" int dde_kit_thread_get_id(struct dde_kit_thread *thread) {
return reinterpret_cast<Dde_kit::Thread_info *>(thread)->id(); }
extern "C" void dde_kit_thread_schedule(void)
{
/* FIXME */
}
/*********************
** Sleep interface **
*********************/
static void _wake_up_msleep(void *lock)
{
reinterpret_cast<Lock *>(lock)->unlock();
}
extern "C" void dde_kit_thread_msleep(unsigned long msecs)
{
/*
* This simple msleep() registers a timer that fires after 'msecs' and
* blocks on 'lock'. The registered timer handler just unlocks 'lock' and
* the sleeping thread unblocks.
*/
Lock *lock;
struct dde_kit_timer *timer;
unsigned long timeout = jiffies + (msecs * DDE_KIT_HZ) / 1000;
lock = new (env()->heap()) Lock(Lock::LOCKED);
timer = dde_kit_timer_add(_wake_up_msleep, lock, timeout);
lock->lock();
dde_kit_timer_del(timer);
destroy((env()->heap()), lock);
}
extern "C" void dde_kit_thread_usleep(unsigned long usecs)
{
unsigned long msecs = usecs / 1000;
if (msecs > 1)
dde_kit_thread_msleep(msecs);
else
dde_kit_thread_schedule();
}
extern "C" void dde_kit_thread_nsleep(unsigned long nsecs)
{
unsigned long msecs = nsecs / 1000000;
if (msecs > 1)
dde_kit_thread_msleep(msecs);
else
dde_kit_thread_schedule();
}

View File

@ -0,0 +1,69 @@
/*
* \brief Thread facility
* \author Christian Helmuth
* \date 2008-10-20
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/thread.h>
#include <util/avl_tree.h>
#ifndef _THREAD_H_
#define _THREAD_H_
namespace Dde_kit {
using namespace Genode;
typedef Genode::Thread<0x2000> Thread;
/*
* The thread information is splitted from the actual (runable) thread, so
* that information for adopted threads can be managed.
*/
class Thread_info : public Avl_node<Thread_info>
{
public:
class Not_found : public Exception { };
private:
Thread_base *_thread_base;
const char *_name;
unsigned _id;
void *_data;
static unsigned _id_counter;
public:
Thread_info(Thread_base *thread_base, const char *name);
~Thread_info();
/** AVL node comparison */
bool higher(Thread_info *info);
/** AVL node lookup */
Thread_info *lookup(Thread_base *thread_base);
/***************
** Accessors **
***************/
Thread_base *thread_base() { return _thread_base; }
const char *name() const { return _name; }
void name(const char *name) { _name = name; }
unsigned id() const { return _id; }
void *data() const { return _data; }
void data(void *data) { _data = data; }
};
}
#endif /* _THREAD_H_ */

207
os/src/lib/dde_kit/timer.cc Normal file
View File

@ -0,0 +1,207 @@
/*
* \brief Timers and ticks
* \author Christian Helmuth
* \date 2008-10-22
*/
/*
* Copyright (C) 2008-2011 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <util/list.h>
#include <os/alarm.h>
#include <timer_session/connection.h>
#include <base/printf.h>
extern "C" {
#include <dde_kit/timer.h>
}
#include "thread.h"
using namespace Genode;
/************************
** Timer tick symbols **
************************/
volatile unsigned long dde_kit_timer_ticks;
extern "C" volatile unsigned long jiffies __attribute__ ((alias ("dde_kit_timer_ticks")));
/***************************
** Timer thread and tick **
***************************/
class Timer_thread : Dde_kit::Thread, public Alarm_scheduler
{
private:
unsigned _period_in_ms;
void(*_init)(void *);
void *_priv;
Timer::Connection _timer;
List<dde_kit_timer> _destroy_list;
Lock _destroy_list_lock;
void _enqueue_destroy(dde_kit_timer *timer)
{
Lock::Guard lock_guard(_destroy_list_lock);
_destroy_list.insert(timer);
}
dde_kit_timer * _dequeue_next_destroy()
{
Lock::Guard lock_guard(_destroy_list_lock);
dde_kit_timer *timer = _destroy_list.first();
if (timer)
_destroy_list.remove(timer);
return timer;
}
public:
Timer_thread(unsigned hz, void(*init)(void *), void *priv)
: Dde_kit::Thread("timer"), _period_in_ms(1000/hz), _init(init), _priv(priv)
{
dde_kit_timer_ticks = 0;
start();
}
void entry()
{
dde_kit_thread_adopt_myself("timer");
/* call provided init function */
if (_init) _init(_priv);
/* timer tick loop */
while (true) {
dde_kit_timer *timer;
/*
* XXX This approach drifts with the execution time of handlers
* and timer destruction.
*/
_timer.msleep(_period_in_ms);
++dde_kit_timer_ticks;
/* execute all scheduled alarms */
Alarm_scheduler::handle(dde_kit_timer_ticks);
/* finish pending alarm object destruction */
while ((timer = _dequeue_next_destroy()))
destroy(env()->heap(), timer);
}
};
/**
* Schedule timer for destruction (garbage collection)
*
* \param timer timer fo destroy
*/
void destroy_timer(dde_kit_timer *timer)
{
_enqueue_destroy(timer);
}
};
static Timer_thread *_timer_thread;
/*************+******
** Timer facility **
********************/
class dde_kit_timer : public Alarm, public List<dde_kit_timer>::Element
{
private:
void (*_handler)(void *); /* handler function */
void *_priv; /* private handler token */
bool _pending; /* true if timer is pending */
protected:
bool on_alarm()
{
/* if timer is really pending, call registered handler function */
if (_pending) {
_handler(_priv);
_pending = false;
}
/* do not schedule again */
return false;
}
public:
dde_kit_timer(void (*handler)(void *), void *priv, unsigned long absolute_timeout)
: _handler(handler), _priv(priv), _pending(true)
{
_timer_thread->schedule_absolute(this, absolute_timeout);
}
bool pending() const { return _pending; }
/**
* Schedule destruction of this timer on next tick
*
* Note: The timed event scheduler (alarm.h) does not allow to modify
* alarm objects in the on_alarm function. But, drivers do this
* frequently when modifying timer objects on timeout occurence.
*/
void destroy()
{
_pending = false;
_timer_thread->destroy_timer(this);
}
};
extern "C" struct dde_kit_timer *dde_kit_timer_add(void (*fn)(void *), void *priv,
unsigned long timeout)
{
try {
return new (env()->heap()) dde_kit_timer(fn, priv, timeout);
} catch (...) {
PERR("timer creation failed");
return 0;
}
}
extern "C" void dde_kit_timer_del(struct dde_kit_timer *timer)
{
try {
timer->destroy();
} catch (...) { }
}
extern "C" int dde_kit_timer_pending(struct dde_kit_timer *timer) {
return timer->pending();
}
extern "C" void dde_kit_timer_init(void(*thread_init)(void *), void *priv)
{
try {
static Timer_thread t(DDE_KIT_HZ, thread_init, priv);
_timer_thread = &t;
} catch (...) {
PERR("Timer thread creation failed");
}
}