dde_ipxe: remove dde_kit

A long long time ago, in a galaxy^W^W^W we used DDE kit to ease the
porting of purely C based drivers. By now it became clear, that we
do not gain that much by following this approach. DDE kit contains
much generic functionality, which is not used or rather not needed
by most ported drivers. Hence, we implement a slim C wrapper on top
of Genode's C++ APIs, that is especially tailored to the driver.

In addition to removing the dependency on DDE kit, the iPXE driver
now uses the server framework and the newly introduced signal based
IRQ handling.

Issue #1456.
devel
Josef Söntgen 8 years ago committed by Christian Helmuth
parent 09e96dfdcd
commit 9606abc146

@ -15,6 +15,10 @@
#ifndef _DDE_IPXE__NIC_H_
#define _DDE_IPXE__NIC_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* Link-state change callback
*/
@ -74,8 +78,14 @@ extern int dde_ipxe_nic_link_state(unsigned if_index);
/**
* Initialize network sub-system
*
* \param ep pointer to Server::Entrypoint
*
* \return number of network devices
*/
extern int dde_ipxe_nic_init(void);
extern int dde_ipxe_nic_init(void *ep);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* _DDE_IPXE__NIC_H_ */

@ -1,9 +1,8 @@
LIB_DIR := $(REP_DIR)/src/lib/dde_ipxe
IPXE_CONTRIB_DIR := $(call select_from_ports,dde_ipxe)/src/lib/dde_ipxe/src
LIBS = dde_kit dde_ipxe_support
SRC_C = nic.c dde.c dummies.c
SRC_CC = dde_support.cc
SRC_C = nic.c dde.c dummies.c
SRC_C += $(addprefix core/, iobuf.c string.c bitops.c list.c random.c)
SRC_C += $(addprefix arch/x86/core/, x86_string.c)
@ -21,7 +20,7 @@ INC_DIR += $(IPXE_CONTRIB_DIR)/include $(IPXE_CONTRIB_DIR) \
CC_WARN = -Wall -Wno-address
CC_OPT += $(addprefix -fno-builtin-, putchar toupper tolower)
CC_OPT += -DARCH=i386 -DPLATFORM=pcbios -include compiler.h -DOBJECT=$(notdir $(*:.o=))
CC_C_OPT += -DARCH=i386 -DPLATFORM=pcbios -include compiler.h -DOBJECT=$(notdir $(*:.o=))
#
# Enable debugging of any iPXE object here via '-Ddebug_<object name>=<level>'.
@ -32,10 +31,11 @@ CC_OPT += -Ddebug_lib=7
#CC_OPT += -Ddebug_netdevice=7
vpath nic.c $(LIB_DIR)
vpath dde.c $(LIB_DIR)
vpath dummies.c $(LIB_DIR)
vpath nic.c $(LIB_DIR)
vpath dde.c $(LIB_DIR)
vpath dummies.c $(LIB_DIR)
vpath dde_support.cc $(LIB_DIR)
vpath %.c $(IPXE_CONTRIB_DIR)
vpath %.c $(IPXE_CONTRIB_DIR)
# vi: set ft=make :

@ -1,5 +0,0 @@
LIB_DIR := $(REP_DIR)/src/lib/dde_ipxe
SRC_CC = dde_support.cc
vpath dde_support.cc $(LIB_DIR)

@ -14,29 +14,3 @@ index 472e140..d5095a7 100644
"shrdl %1, %%edx, %%eax\n\t"
: "=a" ( ticks ) : "i" ( TSC_SHIFT ) : "edx" );
return ticks;
diff --git a/src/include/assert.h b/src/include/assert.h
index 655cbdc..a8016c8 100644
--- a/src/include/assert.h
+++ b/src/include/assert.h
@@ -31,7 +31,7 @@ extern unsigned int assertion_failures;
* to the printf symbol.
*/
extern int __attribute__ (( format ( printf, 1, 2 ) ))
-assert_printf ( const char *fmt, ... ) asm ( "printf" );
+assert_printf ( const char *fmt, ... ) asm ( "ipxe_printf" );
/**
* Assert a condition at run-time.
diff --git a/src/include/compiler.h b/src/include/compiler.h
index e555924..b430e37 100644
--- a/src/include/compiler.h
+++ b/src/include/compiler.h
@@ -263,7 +263,7 @@ REQUEST_EXPANDED ( CONFIG_SYMBOL );
/** printf() for debugging */
extern void __attribute__ (( format ( printf, 1, 2 ) ))
-dbg_printf ( const char *fmt, ... );
+dbg_printf ( const char *fmt, ... ) asm ( "ipxe_printf" );
extern void dbg_autocolourise ( unsigned long id );
extern void dbg_decolourise ( void );
extern void dbg_hex_dump_da ( unsigned long dispaddr,

@ -1 +1 @@
7f8c6baa921f6939d49c2804b5b8c4b16981f261
dd11e6a750e68271c2e7d293e9c1d272f7bc78e0

@ -17,11 +17,9 @@
#include <base/printf.h>
#include <cap_session/connection.h>
#include <nic/component.h>
#include <os/server.h>
/* DDE */
extern "C" {
#include <dde_ipxe/nic.h>
}
namespace Ipxe {
@ -34,6 +32,8 @@ namespace Ipxe {
private:
Server::Entrypoint &_ep;
Nic::Mac_address _mac_addr;
Nic::Rx_buffer_alloc &_alloc;
Nic::Driver_notification &_notify;
@ -49,11 +49,12 @@ namespace Ipxe {
public:
Driver(Nic::Rx_buffer_alloc &alloc, Nic::Driver_notification &notify)
: _alloc(alloc), _notify(notify)
Driver(Server::Entrypoint &ep, Nic::Rx_buffer_alloc &alloc,
Nic::Driver_notification &notify)
: _ep(ep), _alloc(alloc), _notify(notify)
{
PINF("--- init iPXE NIC");
int cnt = dde_ipxe_nic_init();
int cnt = dde_ipxe_nic_init(&ep);
PINF(" number of devices: %d", cnt);
PINF("--- init callbacks");
@ -104,47 +105,58 @@ namespace Ipxe {
void handle_irq(int) { /* not used */ }
};
class Driver_factory : public Nic::Driver_factory
} /* namespace Ipxe */
Ipxe::Driver * Ipxe::Driver::instance = 0;
struct Main
{
Server::Entrypoint &ep;
Genode::Sliced_heap sliced_heap;
struct Factory : public Nic::Driver_factory
{
Server::Entrypoint &ep;
Factory(Server::Entrypoint &ep) : ep(ep) { }
Nic::Driver *create(Nic::Rx_buffer_alloc &alloc,
Nic::Driver_notification &notify)
{
Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(alloc, notify);
return Driver::instance;
Ipxe::Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(ep, alloc, notify);
return Ipxe::Driver::instance;
}
void destroy(Nic::Driver *)
{
Genode::destroy(Genode::env()->heap(), Driver::instance);
Driver::instance = 0;
Genode::destroy(Genode::env()->heap(), Ipxe::Driver::instance);
Ipxe::Driver::instance = 0;
}
};
} /* namespace Ipxe */
Ipxe::Driver * Ipxe::Driver::instance = 0;
} factory;
Nic::Root root;
int main(int, char **)
{
using namespace Genode;
printf("--- iPXE NIC driver started ---\n");
/**
* Factory used by 'Nic::Root' at session creation/destruction time
*/
static Ipxe::Driver_factory driver_factory;
Main(Server::Entrypoint &ep)
:
ep(ep),
sliced_heap(Genode::env()->ram_session(), Genode::env()->rm_session()),
factory(ep),
root(&ep.rpc_ep(), &sliced_heap, factory)
{
PINF("--- iPXE NIC driver started ---\n");
Genode::env()->parent()->announce(ep.manage(root));
}
};
enum { STACK_SIZE = 2*sizeof(addr_t)*1024 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "nic_ep");
static Nic::Root nic_root(&ep, env()->heap(), driver_factory);
env()->parent()->announce(ep.manage(&nic_root));
/************
** Server **
************/
sleep_forever();
return 0;
namespace Server {
char const *name() { return "nic_drv_ep"; }
size_t stack_size() { return 2*1024*sizeof(long); }
void construct(Entrypoint &ep) { static Main server(ep); }
}

@ -1,3 +1,3 @@
TARGET = nic_drv
LIBS = dde_ipxe_nic
LIBS = base server dde_ipxe_nic
SRC_CC = main.cc

@ -11,12 +11,13 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode */
/* Genode include */
#include <base/env.h>
#include <base/sleep.h>
#include <base/printf.h>
#include <cap_session/connection.h>
#include <nic/component.h>
#include <os/server.h>
#include <nic/stat.h>
#include <nic/packet_allocator.h>
@ -56,11 +57,12 @@ namespace Ipxe {
public:
Driver(Nic::Rx_buffer_alloc &alloc, Nic::Driver_notification &notify)
Driver(Server::Entrypoint &ep, Nic::Rx_buffer_alloc &alloc,
Nic::Driver_notification &notify)
: _alloc(alloc), _notify(notify), _stat(_timer)
{
PINF("--- init iPXE NIC");
int cnt = dde_ipxe_nic_init();
int cnt = dde_ipxe_nic_init(&ep);
PINF(" number of devices: %d", cnt);
PINF("--- init callbacks");
@ -119,57 +121,61 @@ namespace Ipxe {
void handle_irq(int) { /* not used */ }
};
} /* namespace Ipxe */
Ipxe::Driver * Ipxe::Driver::instance = 0;
class Driver_factory : public Nic::Driver_factory
struct Main
{
Server::Entrypoint &ep;
Genode::Sliced_heap sliced_heap;
struct Factory : public Nic::Driver_factory
{
Nic::Driver *create(Nic::Rx_buffer_alloc &alloc, Nic::Driver_notification &notify)
Server::Entrypoint &ep;
Factory(Server::Entrypoint &ep) : ep(ep) { }
Nic::Driver *create(Nic::Rx_buffer_alloc &alloc,
Nic::Driver_notification &notify)
{
Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(alloc, notify);
return Driver::instance;
Ipxe::Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(ep, alloc, notify);
return Ipxe::Driver::instance;
}
void destroy(Nic::Driver *)
{
Genode::destroy(Genode::env()->heap(), Driver::instance);
Driver::instance = 0;
Genode::destroy(Genode::env()->heap(), Ipxe::Driver::instance);
Ipxe::Driver::instance = 0;
}
};
} /* namespace Ipxe */
Ipxe::Driver * Ipxe::Driver::instance = 0;
} factory;
Nic::Root root;
int main(int, char **)
{
using namespace Genode;
printf("--- iPXE NIC driver started ---\n");
Main(Server::Entrypoint &ep)
:
ep(ep),
sliced_heap(Genode::env()->ram_session(), Genode::env()->rm_session()),
factory(ep),
root(&ep.rpc_ep(), &sliced_heap, factory)
{
PINF("--- iPXE NIC driver started ---\n");
Genode::env()->parent()->announce(ep.manage(root));
/**
* Factory used by 'Nic::Root' at session creation/destruction time
*/
static Ipxe::Driver_factory driver_factory;
root.session("ram_quota=155648, tx_buf_size=65536, rx_buf_size=65536",
Genode::Affinity());
}
};
enum { STACK_SIZE = 2*sizeof(addr_t)*1024 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "nic_ep");
static Nic::Root nic_root(&ep, env()->heap(), driver_factory);
env()->parent()->announce(ep.manage(&nic_root));
/************
** Server **
************/
/*
Genode::size_t tx_buf_size = 64*1024;
Genode::size_t rx_buf_size = 64*1024;
session("ram_quota=%zd, tx_buf_size=%zd, rx_buf_size=%zd",
6*4096 + tx_buf_size + rx_buf_size,
tx_buf_size, rx_buf_size))
*/
nic_root.session("ram_quota=155648, tx_buf_size=65536, rx_buf_size=65536",
Affinity());
sleep_forever();
return 0;
namespace Server {
char const *name() { return "nic_drv_stat_ep"; }
size_t stack_size() { return 2*1024*sizeof(long); }
void construct(Entrypoint &ep) { static Main server(ep); }
}

@ -1,3 +1,3 @@
TARGET = nic_drv_stat
LIBS = dde_ipxe_nic net-stat
LIBS = base server dde_ipxe_nic net-stat
SRC_CC = main.cc

@ -1,24 +1,17 @@
/*
* \brief DDE iPXE emulation implementation
* \author Christian Helmuth
* \author Josef Soentgen
* \date 2010-09-13
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
* Copyright (C) 2010-2015 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.
*/
/* DDE kit */
#include <dde_kit/memory.h>
#include <dde_kit/resources.h>
#include <dde_kit/pci.h>
#include <dde_kit/pgtab.h>
#include <dde_kit/lock.h>
#include <dde_kit/timer.h>
/* iPXE */
#include <stdlib.h>
#include <ipxe/io.h>
@ -28,92 +21,35 @@
#include <ipxe/settings.h>
#include <ipxe/netdevice.h>
#include <ipxe/timer2.h>
/* local includes */
#include <dde_support.h>
#include "local.h"
#define PDBG(fmt, ...) dde_printf(fmt "\n", ##__VA_ARGS__)
/***********************************
** Wrapper to DDE support in C++ **
***********************************/
#include "dde_support.h"
/***************************
** DMA memory allocation **
***************************/
void *alloc_memblock(size_t size, size_t align, size_t offset) { return dde_alloc_memblock(size, align, offset); }
void free_memblock(void *p, size_t size) { dde_free_memblock(p, size); }
void timer2_udelay(unsigned long usecs) { dde_timer2_udelay(usecs); }
void *alloc_memblock(size_t size, size_t align, size_t offset) {
return dde_dma_alloc(size, align, offset); }
/**********************************
** Memory pool in DDE kit slabs **
**********************************/
enum { SLAB_128, SLAB_256, SLAB_512, SLAB_1024, SLAB_2048, SLAB_4096, SLAB_20480, NUM_SLABS };
void free_memblock(void *p, size_t size) {
dde_dma_free(p, size); }
static struct dde_kit_slab *slabs[NUM_SLABS];
static inline void *alloc_from_slab(size_t size)
{
size_t *p = 0;
size_t alloc_size = size + sizeof(size_t);
if (alloc_size <= 128)
p = dde_kit_slab_alloc(slabs[SLAB_128]);
else if (alloc_size <= 256)
p = dde_kit_slab_alloc(slabs[SLAB_256]);
else if (alloc_size <= 512)
p = dde_kit_slab_alloc(slabs[SLAB_512]);
else if (alloc_size <= 1024)
p = dde_kit_slab_alloc(slabs[SLAB_1024]);
else if (alloc_size <= 2048)
p = dde_kit_slab_alloc(slabs[SLAB_2048]);
else if (alloc_size <= 4096)
p = dde_kit_slab_alloc(slabs[SLAB_4096]);
else if (alloc_size <= 20480)
p = dde_kit_slab_alloc(slabs[SLAB_20480]);
else
LOG("allocation of size %zd too big", size);
/**********************
** Slab memory pool **
**********************/
if (p) {
*p = alloc_size;
p++;
}
static inline void *alloc_from_slab(size_t size) {
return dde_slab_alloc(size); }
return p;
}
static inline void free_in_slab(void *p0)
{
size_t *p = (size_t *)p0 - 1;
if (*p <= 128)
dde_kit_slab_free(slabs[SLAB_128], p);
else if (*p <= 256)
dde_kit_slab_free(slabs[SLAB_256], p);
else if (*p <= 512)
dde_kit_slab_free(slabs[SLAB_512], p);
else if (*p <= 1024)
dde_kit_slab_free(slabs[SLAB_1024], p);
else if (*p <= 2048)
dde_kit_slab_free(slabs[SLAB_2048], p);
else if (*p <= 4096)
dde_kit_slab_free(slabs[SLAB_4096], p);
else if (*p <= 20480)
dde_kit_slab_free(slabs[SLAB_20480], p);
else
LOG("deallocation at %p not possible", p0);
}
void slab_init(void)
{
slabs[SLAB_128] = dde_kit_slab_init(128);
slabs[SLAB_256] = dde_kit_slab_init(256);
slabs[SLAB_512] = dde_kit_slab_init(512);
slabs[SLAB_1024] = dde_kit_slab_init(1024);
slabs[SLAB_2048] = dde_kit_slab_init(2048);
slabs[SLAB_4096] = dde_kit_slab_init(4096);
slabs[SLAB_20480] = dde_kit_slab_init(20480);
}
static inline void free_in_slab(void *p) {
dde_slab_free(p); }
/************
@ -131,23 +67,23 @@ void *zalloc(size_t size)
}
void * malloc(size_t size)
{
return alloc_from_slab(size);
}
void *malloc(size_t size) {
return alloc_from_slab(size); }
void free(void *p)
{
free_in_slab(p);
}
void free(void *p) {
free_in_slab(p); }
/*********************
** Time and Timers **
*********************/
void udelay (unsigned long usecs)
void timer2_udelay(unsigned long usecs) {
dde_udelay(usecs); }
void udelay(unsigned long usecs)
{
static int init = 0;
@ -166,13 +102,11 @@ void udelay (unsigned long usecs)
}
void mdelay (unsigned long msecs)
{
dde_kit_thread_msleep(msecs);
}
void mdelay(unsigned long msecs) {
dde_mdelay(msecs); }
int ipxe_printf(const char *format, ...)
int printf(const char *format, ...)
{
/* replace unsupported '%#' with 'x%' in format string */
char *new_format = (char *)malloc(strlen(format) + 1);
@ -192,7 +126,7 @@ int ipxe_printf(const char *format, ...)
va_list va;
va_start(va, format);
dde_kit_vprintf(new_format, va);
dde_vprintf(new_format, va);
va_end(va);
free(new_format);
@ -207,17 +141,16 @@ int ipxe_printf(const char *format, ...)
void iounmap(volatile const void *io_addr)
{
LOG("io_addr = %p", io_addr);
/* XXX DDE kit always releases the whole region */
dde_kit_release_mem((dde_kit_addr_t) io_addr, 1);
dde_release_iomem((dde_addr_t) io_addr, 1);
}
void * ioremap(unsigned long bus_addr, size_t len)
void *ioremap(unsigned long bus_addr, size_t len)
{
LOG("bus_addr = %p len = %zx", (void *)bus_addr, len);
dde_kit_addr_t vaddr;
dde_addr_t vaddr;
int ret = dde_kit_request_mem(bus_addr, len, 0, &vaddr);
int ret = dde_request_iomem(bus_addr, len, 0, &vaddr);
return ret ? 0 : (void *)vaddr;
}
@ -225,7 +158,7 @@ void * ioremap(unsigned long bus_addr, size_t len)
unsigned long user_to_phys(userptr_t userptr, off_t offset)
{
return dde_kit_pgtab_get_physaddr((void *)userptr) + offset;
return dde_dma_get_physaddr((void *)userptr) + offset;
}
@ -247,54 +180,42 @@ unsigned long phys_to_bus(unsigned long phys_addr)
int pci_read_config_byte(struct pci_device *pci, unsigned int where, uint8_t *value)
{
dde_kit_pci_readb(PCI_BUS(pci->busdevfn), PCI_SLOT(pci->busdevfn), PCI_FUNC(pci->busdevfn),
where, value);
dde_pci_readb(where, value);
return 0;
}
int pci_read_config_word(struct pci_device *pci, unsigned int where, uint16_t *value)
{
dde_kit_pci_readw(PCI_BUS(pci->busdevfn), PCI_SLOT(pci->busdevfn), PCI_FUNC(pci->busdevfn),
where, value);
dde_pci_readw( where, value);
return 0;
}
int pci_read_config_dword(struct pci_device *pci, unsigned int where, uint32_t *value)
{
dde_kit_pci_readl(PCI_BUS(pci->busdevfn), PCI_SLOT(pci->busdevfn), PCI_FUNC(pci->busdevfn),
where, value);
dde_pci_readl(where, value);
return 0;
}
int pci_write_config_byte(struct pci_device *pci, unsigned int where, uint8_t value)
{
dde_kit_pci_writeb(PCI_BUS(pci->busdevfn), PCI_SLOT(pci->busdevfn), PCI_FUNC(pci->busdevfn),
where, value);
dde_pci_writeb(where, value);
return 0;
}
int pci_write_config_word(struct pci_device *pci, unsigned int where, uint16_t value)
{
dde_kit_pci_writew(PCI_BUS(pci->busdevfn), PCI_SLOT(pci->busdevfn), PCI_FUNC(pci->busdevfn),
where, value);
dde_pci_writew(where, value);
return 0;
}
int pci_write_config_dword(struct pci_device *pci, unsigned int where, uint32_t value)
{
dde_kit_pci_writel(PCI_BUS(pci->busdevfn), PCI_SLOT(pci->busdevfn), PCI_FUNC(pci->busdevfn),
where, value);
dde_pci_writel( where, value);
return 0;
}

@ -1,28 +1,313 @@
/*
* \brief Functions not offered by Genode's DDE-kit
* \brief DDE iPXE wrappers to C++ backend
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2010-10-21
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
* Copyright (C) 2010-2015 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.
*/
/*
* The build system picks up stdarg.h from iPXE instead of the one
* provided by GCC. This header contains the FILE_LICENCE macro which
* is defined by iPXE's compiler.h.
*/
#define FILE_LICENCE(x)
/* Genode includes */
#include <base/allocator_avl.h>
#include <base/env.h>
#include <base/printf.h>
#include <base/slab.h>
#include <base/sleep.h>
#include <dataspace/client.h>
#include <io_mem_session/connection.h>
#include <io_port_session/connection.h>
#include <irq_session/connection.h>
#include <os/server.h>
#include <pci_device/client.h>
#include <pci_session/connection.h>
#include <rm_session/connection.h>
#include <timer_session/connection.h>
#include <util/misc_math.h>
/* local includes */
#include <dde_support.h>
//using namespace Genode;
/****************
** Migriation **
****************/
static Server::Entrypoint *_ep;
extern "C" void dde_init(void *ep)
{
_ep = (Server::Entrypoint*)ep;
}
/************
** printf **
************/
extern "C" void dde_vprintf(const char *fmt, va_list va) {
Genode::vprintf(fmt, va); }
extern "C" void dde_printf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
dde_vprintf(fmt, args);
va_end(args);
}
/***********
** Timer **
***********/
extern "C" void dde_udelay(unsigned long usecs)
{
/*
* This function is called only once during rdtsc calibration (usecs will be
* 10000, see dde.c 'udelay'. We do not use DDE timers here, since Genode's
* timer connection is the most precise one around.
*/
Timer::Connection timer;
timer.usleep(usecs);
}
/***************************
** locking/synchronizing **
***************************/
/**
* DDE iPXE mutual exclusion lock
*/
static Genode::Lock _ipxe_lock;
extern "C" void dde_lock_enter(void) { _ipxe_lock.lock(); }
extern "C" void dde_lock_leave(void) { _ipxe_lock.unlock(); }
extern "C" void dde_mdelay(unsigned long msecs)
{
/*
* Using one static timer connection here is safe because
* this function is only called while initializing the device
* and only be the same thread.
*/
static Timer::Connection timer;
timer.msleep(msecs);
}
/******************
** PCI handling **
******************/
struct Pci_driver
{
enum {
PCI_BASE_CLASS_NETWORK = 0x02,
CLASS_MASK = 0xff0000,
CLASS_NETWORK = PCI_BASE_CLASS_NETWORK << 16
};
Pci::Connection _pci;
Pci::Device_capability _cap;
Pci::Device_capability _last_cap;
struct Region
{
Genode::addr_t base;
Genode::addr_t mapped_base;
} _region;
template <typename T>
Pci::Device::Access_size _access_size(T t)
{
switch (sizeof(T)) {
case 1:
return Pci::Device::ACCESS_8BIT;
case 2:
return Pci::Device::ACCESS_16BIT;
default:
return Pci::Device::ACCESS_32BIT;
}
}
void _bus_address(int *bus, int *dev, int *fun)
{
Pci::Device_client client(_cap);
unsigned char b, d, f;
client.bus_address(&b, &d, &f);
*bus = b;
*dev = d;
*fun = f;
}
Pci_driver() { }
template <typename T>
void config_read(unsigned int devfn, T *val)
{
Pci::Device_client client(_cap);
*val = client.config_read(devfn, _access_size(*val));
}
template <typename T>
void config_write(unsigned int devfn, T val)
{
Pci::Device_client client(_cap);
client.config_write(devfn, val, _access_size(val));
}
int first_device(int *bus, int *dev, int *fun)
{
_cap = _pci.first_device(CLASS_NETWORK, CLASS_MASK);
_bus_address(bus, dev, fun);
return 0;
}
int next_device(int *bus, int *dev, int *fun)
{
_last_cap = _cap;
_cap = _pci.next_device(_cap, CLASS_NETWORK, CLASS_MASK);
_bus_address(bus, dev, fun);
if (_last_cap.valid())
_pci.release_device(_last_cap);
return 0;
}
Genode::addr_t alloc_dma_memory(Genode::size_t size)
{
try {
using namespace Genode;
/* trigger that the device gets assigned to this driver */
_pci.config_extended(_cap);
Ram_dataspace_capability ram_cap;
ram_cap = _pci.alloc_dma_buffer(_cap, size);
_region.mapped_base = (Genode::addr_t)env()->rm_session()->attach(ram_cap);
_region.base = Dataspace_client(ram_cap).phys_addr();
return _region.mapped_base;
} catch (...) { return 0; }
}
Genode::addr_t virt_to_phys(Genode::addr_t virt) {
return virt - _region.mapped_base + _region.base; }
};
static Pci_driver& pci_drv()
{
static Pci_driver _pci_drv;
return _pci_drv;
}
extern "C" int dde_pci_first_device(int *bus, int *dev, int *fun) {
return pci_drv().first_device(bus, dev, fun); }
extern "C" int dde_pci_next_device(int *bus, int *dev, int *fun) {
return pci_drv().next_device(bus, dev, fun); }
extern "C" void dde_pci_readb(int pos, dde_uint8_t *val) {
pci_drv().config_read(pos, val); }
extern "C" void dde_pci_readw(int pos, dde_uint16_t *val) {
pci_drv().config_read(pos, val); }
extern "C" void dde_pci_readl(int pos, dde_uint32_t *val) {
pci_drv().config_read(pos, val); }
extern "C" void dde_pci_writeb(int pos, dde_uint8_t val) {
pci_drv().config_write(pos, val); }
extern "C" void dde_pci_writew(int pos, dde_uint16_t val) {
pci_drv().config_write(pos, val); }
extern "C" void dde_pci_writel(int pos, dde_uint32_t val) {
pci_drv().config_write(pos, val); }
/************************
** Interrupt handling **
************************/
struct Irq_handler
{
Server::Entrypoint &ep;
Genode::Irq_connection irq;
Genode::Signal_rpc_member<Irq_handler> dispatcher;
typedef void (*irq_handler)(void*);
irq_handler handler;
void *priv;
void handle(unsigned)
{
handler(priv);
irq.ack_irq();
}
Irq_handler(Server::Entrypoint &ep, int irqnr,
irq_handler handler, void *priv)
:
ep(ep), irq(irqnr), dispatcher(ep, *this, &Irq_handler::handle),
handler(handler), priv(priv)
{
irq.sigh(dispatcher);
/* intial ack so that we will receive IRQ signals */
irq.ack_irq();
}
};
static Irq_handler *_irq_handler;
extern "C" int dde_interrupt_attach(int irq, void(*handler)(void *), void *priv)
{
if (_irq_handler) {
PERR("Irq_handler already registered");
Genode::sleep_forever();
}
try {
_irq_handler = new (Genode::env()->heap())
Irq_handler(*_ep, irq, handler, priv);
} catch (...) { return -1; }
extern "C" {
#include <dde_kit/pci.h>
#include "dde_support.h"
return 0;
}
using namespace Genode;
/***************************************************
** Support for aligned and DMA memory allocation **
@ -31,56 +316,320 @@ using namespace Genode;
enum { BACKING_STORE_SIZE = 1024 * 1024 };
static Allocator_avl& allocator()
static Genode::Allocator_avl& allocator()
{
static Allocator_avl _avl(env()->heap());
static Genode::Allocator_avl _avl(Genode::env()->heap());
return _avl;
}
extern "C" int dde_mem_init(int bus, int dev, int func)
extern "C" int dde_dma_mem_init()
{
try {
addr_t base = dde_kit_pci_alloc_dma_buffer(bus, dev, func,
BACKING_STORE_SIZE);
Genode::addr_t base = pci_drv().alloc_dma_memory(BACKING_STORE_SIZE);
/* add to allocator */
allocator().add_range(base, BACKING_STORE_SIZE);
} catch (...) {
return false;
}
} catch (...) { return false; }
return true;
}
extern "C" void *dde_alloc_memblock(dde_kit_size_t size, dde_kit_size_t align,
dde_kit_size_t offset)
extern "C" void *dde_dma_alloc(dde_size_t size, dde_size_t align,
dde_size_t offset)
{
void *ptr;
if (allocator().alloc_aligned(size, &ptr, log2(align)).is_error()) {
PERR("memory allocation failed in alloc_memblock (size=%zd, align=%zx,"
" offset=%zx)", size, align, offset);
if (allocator().alloc_aligned(size, &ptr, Genode::log2(align)).is_error()) {
PERR("memory allocation failed in alloc_memblock (size=%zu, align=%zx,"
" offset=%zx)", (Genode::size_t)size, (Genode::size_t)align, (Genode::size_t)offset);
return 0;
}
return ptr;
}
extern "C" void dde_free_memblock(void *p, dde_kit_size_t size)
extern "C" void dde_dma_free(void *p, dde_size_t size) {
allocator().free(p, size); }
extern "C" dde_addr_t dde_dma_get_physaddr(void *virt) {
return pci_drv().virt_to_phys((Genode::addr_t)virt); }
/**************
** I/O port **
**************/
static Genode::Io_port_connection *_io_port;
extern "C" void dde_request_io(dde_addr_t base, dde_size_t size)
{
allocator().free(p, size);
using namespace Genode;
if (_io_port) {
PERR("Io_port_connection already open");
sleep_forever();
}
_io_port = new (env()->heap()) Io_port_connection(base, size);
}
/***********
** Timer **
***********/
extern "C" dde_uint8_t dde_inb(dde_addr_t port) {
return _io_port->inb(port); }
extern "C" dde_uint16_t dde_inw(dde_addr_t port) {
return _io_port->inw(port); }
extern "C" dde_uint32_t dde_inl(dde_addr_t port) {
return _io_port->inl(port); }
extern "C" void dde_outb(dde_addr_t port, dde_uint8_t data) {
_io_port->outb(port, data); }
extern "C" void dde_outw(dde_addr_t port, dde_uint16_t data) {
_io_port->outw(port, data); }
extern "C" void dde_timer2_udelay(unsigned long usecs)
extern "C" void dde_outl(dde_addr_t port, dde_uint32_t data) {
_io_port->outl(port, data); }
/**********************
** Slab memory pool **
**********************/
struct Slab_backend_alloc : public Genode::Allocator,
public Genode::Rm_connection
{
enum {
VM_SIZE = 512 * 1024,
BLOCK_SIZE = 64 * 1024,
ELEMENTS = VM_SIZE / BLOCK_SIZE,
};
Genode::addr_t _base;
Genode::Ram_dataspace_capability _ds_cap[ELEMENTS];
int _index;
Genode::Allocator_avl _range;
Genode::Ram_session &_ram;
bool _alloc_block()
{
using namespace Genode;
if (_index == ELEMENTS) {
PERR("Slab-backend exhausted!");
return false;
}
try {
_ds_cap[_index] = _ram.alloc(BLOCK_SIZE);
Rm_connection::attach_at(_ds_cap[_index], _index * BLOCK_SIZE, BLOCK_SIZE, 0);
} catch (...) { return false; }
/* return base + offset in VM area */
Genode::addr_t block_base = _base + (_index * BLOCK_SIZE);
++_index;
_range.add_range(block_base, BLOCK_SIZE);
return true;
}
Slab_backend_alloc(Genode::Ram_session &ram)
:
Rm_connection(0, VM_SIZE),
_index(0), _range(Genode::env()->heap()), _ram(ram)
{
/* reserver attach us, anywere */
_base = Genode::env()->rm_session()->attach(dataspace());
}
Genode::addr_t start() const { return _base; }
Genode::addr_t end() const { return _base + VM_SIZE - 1; }
/*************************
** Allocator interface **
*************************/
bool alloc(Genode::size_t size, void **out_addr)
{
bool done = _range.alloc(size, out_addr);
if (done)
return done;
done = _alloc_block();
if (!done) {
PERR("Backend allocator exhausted\n");
return false;
}
return _range.alloc(size, out_addr);
}
void free(void *addr, Genode::size_t size) { }
Genode::size_t overhead(Genode::size_t size) const { return 0; }
bool need_size_for_free() const { return false; }
};
struct Slab_alloc : public Genode::Slab
{
/*
* This function is called only once during rdtsc calibration (usecs will be
* 10000, see dde.c 'udelay'. We do not use DDE timers here, since Genode's
* timer connection is the most precise one around.
* Each slab block in the slab contains about 8 objects (slab entries)
* as proposed in the paper by Bonwick and block sizes are multiples of
* page size.
*/
static Genode::size_t _calculate_block_size(Genode::size_t object_size)
{
Genode::size_t block_size = 8 * (object_size + sizeof(Genode::Slab_entry))
+ sizeof(Genode::Slab_block);
return Genode::align_addr(block_size, 12);
}
Slab_alloc(Genode::size_t object_size, Slab_backend_alloc &allocator)
: Slab(object_size, _calculate_block_size(object_size), 0, &allocator) { }
/**
* Convenience slabe-entry allocation
*/
Timer::Connection timer;
timer.usleep(usecs);
Genode::addr_t alloc()
{
Genode::addr_t result;
return (Slab::alloc(slab_size(), (void **)&result) ? result : 0);
}
};
struct Slab
{
enum {
SLAB_START_LOG2 = 5, /* 32 B */
SLAB_STOP_LOG2 = 10, /* 1 KiB */
NUM_SLABS = (SLAB_STOP_LOG2 - SLAB_START_LOG2) + 1,
};
Slab_backend_alloc &_back_alloc;
Slab_alloc *_allocator[NUM_SLABS];
Genode::addr_t _start;
Genode::addr_t _end;
Slab(Slab_backend_alloc &alloc)
: _back_alloc(alloc), _start(alloc.start()), _end(alloc.end())
{
for (unsigned i = 0; i < NUM_SLABS; i++)
_allocator[i] = new (Genode::env()->heap())
Slab_alloc(1U << (SLAB_START_LOG2 + i), alloc);
}
void *alloc(Genode::size_t size)
{
using namespace Genode;
size += sizeof(Genode::addr_t);
int msb = Genode::log2(size);
if (size > (1U << msb))
msb++;
if (size < (1U << SLAB_START_LOG2))
msb = SLAB_STOP_LOG2;
if (msb > SLAB_STOP_LOG2)
return 0;
Genode::addr_t addr = _allocator[msb - SLAB_START_LOG2]->alloc();
if (!addr)
return 0;
*(Genode::addr_t*)addr = msb - SLAB_START_LOG2;
addr += sizeof(Genode::addr_t);
return (void*)addr;
}
void free(void *p)
{
using namespace Genode;
Genode::addr_t *addr = ((Genode::addr_t *)p)-1;
unsigned index = *(unsigned*)(addr);
_allocator[index]->free((void*)(addr));
}
};
static ::Slab& slab()
{
static ::Slab_backend_alloc sb(*Genode::env()->ram_session());
static ::Slab s(sb);
return s;
}
extern "C" void *dde_slab_alloc(dde_size_t size) {
return slab().alloc(size); }
extern "C" void dde_slab_free(void *p) {
slab().free(p); }
/****************
** I/O memory **
****************/
struct Io_memory
{
Genode::Io_mem_connection _mem;
Genode::Io_mem_dataspace_capability _mem_ds;
Genode::addr_t _vaddr;
Io_memory(Genode::addr_t base, Genode::size_t size, bool wc)
:
_mem(base, size, wc),
_mem_ds(_mem.dataspace())
{
if (!_mem_ds.valid())
throw Genode::Exception();
_vaddr = Genode::env()->rm_session()->attach(_mem_ds);
_vaddr |= base & 0xfff;
}
Genode::addr_t vaddr() const { return _vaddr; }
};
static Io_memory *_io_mem;
extern "C" int dde_request_iomem(dde_addr_t start, dde_size_t size, int wc,
dde_addr_t *vaddr)
{
if (_io_mem) {
PERR("Io_memory already requested");
Genode::sleep_forever();
}
try {
_io_mem = new (Genode::env()->heap()) Io_memory(start, size, !!wc);
} catch (...) { return -1; }
*vaddr = _io_mem->vaddr();
return 0;
}
extern "C" int dde_release_iomem(dde_addr_t start, dde_size_t size)
{
try {
destroy(Genode::env()->heap(), _io_mem);
_io_mem = 0;
return 0;
} catch (...) { return -1; }
}

@ -1,26 +0,0 @@
/*
* \brief DDE iPXE wrappers to C++ backend
* \author Christian Helmuth
* \date 2013-01-07
*/
/*
* Copyright (C) 2010-2013 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 _DDE_SUPPORT_H_
#define _DDE_SUPPORT_H_
#include <dde_kit/types.h>
void *dde_alloc_memblock(dde_kit_size_t size, dde_kit_size_t align,
dde_kit_size_t offset);
void dde_free_memblock(void *p, dde_kit_size_t size);
void dde_timer2_udelay(unsigned long usecs);
int dde_mem_init(int bus, int dev, int func);
#endif /* _DDE_SUPPORT_H_ */

@ -11,7 +11,9 @@
* under the terms of the GNU General Public License version 2.
*/
#include "local.h"
#include <dde_support.h>
#define TRACE dde_printf("\033[35m%s not implemented\033[0m\n", __func__)
int snprintf(char *buf, __SIZE_TYPE__ size, const char *fmt, ...) { TRACE; return 0; }

@ -0,0 +1,128 @@
/*
* \brief DDE iPXE wrappers to C++ backend
* \author Christian Helmuth
* \author Josef Soentgen
* \date 2013-01-07
*/
/*
* Copyright (C) 2010-2015 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 _DDE_SUPPORT_H_
#define _DDE_SUPPORT_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned long dde_addr_t;
typedef unsigned long dde_size_t;
typedef unsigned char dde_uint8_t;
typedef unsigned short dde_uint16_t;
typedef unsigned int dde_uint32_t;
/*****************
** Initialization
*****************/
void dde_init(void *ep);
/***********
** Timer **
***********/
void dde_udelay(unsigned long usecs);
void dde_mdelay(unsigned long msecs);
/************
** printf **
************/
typedef __builtin_va_list va_list;
void dde_vprintf(const char *fmt, va_list va) __attribute__ ((format (printf, 1, 0)));
void dde_printf(const char *fmt, ...);
/***************************************************
** Support for aligned and DMA memory allocation **
***************************************************/
int dde_dma_mem_init();
void *dde_dma_alloc(dde_size_t size, dde_size_t align, dde_size_t offset);
void dde_dma_free(void *p, dde_size_t size);
dde_addr_t dde_dma_get_physaddr(void *virt);
/***************************
** locking/synchronizing **
***************************/
void dde_lock_enter(void);
void dde_lock_leave(void);
/************************
** Interrupt handling **
************************/
int dde_interrupt_attach(int irq, void (*handler)(void *), void *priv);
/******************
** PCI handling **
******************/
int dde_pci_first_device(int *, int *, int *);