2011-12-22 16:19:25 +01:00
|
|
|
/*
|
2015-03-26 13:47:14 +01:00
|
|
|
* \brief DDE iPXE wrappers to C++ backend
|
2011-12-22 16:19:25 +01:00
|
|
|
* \author Sebastian Sumpf
|
2015-03-26 13:47:14 +01:00
|
|
|
* \author Josef Soentgen
|
2011-12-22 16:19:25 +01:00
|
|
|
* \date 2010-10-21
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2015-03-26 13:47:14 +01:00
|
|
|
* Copyright (C) 2010-2015 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
2015-03-26 13:47:14 +01:00
|
|
|
/*
|
|
|
|
* 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 */
|
2011-12-22 16:19:25 +01:00
|
|
|
#include <base/allocator_avl.h>
|
|
|
|
#include <base/env.h>
|
|
|
|
#include <base/printf.h>
|
2015-03-26 13:47:14 +01:00
|
|
|
#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>
|
2011-12-22 16:19:25 +01:00
|
|
|
#include <timer_session/connection.h>
|
|
|
|
#include <util/misc_math.h>
|
2015-03-26 13:47:14 +01:00
|
|
|
/* 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 */
|
2015-04-10 20:52:21 +02:00
|
|
|
for (unsigned i = 0; i < 2; i++) {
|
|
|
|
try {
|
|
|
|
_pci.config_extended(_cap);
|
|
|
|
break;
|
|
|
|
} catch (Pci::Device::Quota_exceeded) {
|
|
|
|
Genode::env()->parent()->upgrade(_pci.cap(), "ram_quota=4096");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* transfer quota to pci driver, otherwise it will give us a exception */
|
|
|
|
char buf[32];
|
|
|
|
Genode::snprintf(buf, sizeof(buf), "ram_quota=%zd", size);
|
|
|
|
Genode::env()->parent()->upgrade(_pci.cap(), buf);
|
|
|
|
|
|
|
|
Ram_dataspace_capability ram_cap = _pci.alloc_dma_buffer(size);
|
|
|
|
|
2015-03-26 13:47:14 +01:00
|
|
|
_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;
|
2015-04-10 13:47:43 +02:00
|
|
|
Genode::Irq_session_client irq;
|
2015-03-26 13:47:14 +01:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2015-04-10 13:47:43 +02:00
|
|
|
Irq_handler(Server::Entrypoint &ep, Genode::Irq_session_capability cap,
|
2015-03-26 13:47:14 +01:00
|
|
|
irq_handler handler, void *priv)
|
|
|
|
:
|
2015-04-10 13:47:43 +02:00
|
|
|
ep(ep), irq(cap), dispatcher(ep, *this, &Irq_handler::handle),
|
2015-03-26 13:47:14 +01:00
|
|
|
handler(handler), priv(priv)
|
|
|
|
{
|
|
|
|
irq.sigh(dispatcher);
|
|
|
|
|
|
|
|
/* intial ack so that we will receive IRQ signals */
|
|
|
|
irq.ack_irq();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static Irq_handler *_irq_handler;
|
|
|
|
|
2015-04-10 13:47:43 +02:00
|
|
|
extern "C" int dde_interrupt_attach(void(*handler)(void *), void *priv)
|
2015-03-26 13:47:14 +01:00
|
|
|
{
|
|
|
|
if (_irq_handler) {
|
|
|
|
PERR("Irq_handler already registered");
|
|
|
|
Genode::sleep_forever();
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2015-04-10 13:47:43 +02:00
|
|
|
Pci::Device_client device(pci_drv()._cap);
|
2015-03-26 13:47:14 +01:00
|
|
|
_irq_handler = new (Genode::env()->heap())
|
2015-04-10 13:47:43 +02:00
|
|
|
Irq_handler(*_ep, device.irq(0), handler, priv);
|
2015-03-26 13:47:14 +01:00
|
|
|
} catch (...) { return -1; }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-26 13:47:14 +01:00
|
|
|
return 0;
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
2015-03-26 13:47:14 +01:00
|
|
|
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-02-21 13:45:39 +01:00
|
|
|
/***************************************************
|
|
|
|
** Support for aligned and DMA memory allocation **
|
|
|
|
***************************************************/
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
enum { BACKING_STORE_SIZE = 1024 * 1024 };
|
|
|
|
|
|
|
|
|
2015-03-26 13:47:14 +01:00
|
|
|
static Genode::Allocator_avl& allocator()
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2015-03-26 13:47:14 +01:00
|
|
|
static Genode::Allocator_avl _avl(Genode::env()->heap());
|
2013-02-21 13:45:39 +01:00
|
|
|
return _avl;
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
2015-03-26 13:47:14 +01:00
|
|
|
|
|
|
|
extern "C" int dde_dma_mem_init()
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
|
|
|
try {
|
2015-03-26 13:47:14 +01:00
|
|
|
Genode::addr_t base = pci_drv().alloc_dma_memory(BACKING_STORE_SIZE);
|
2011-12-22 16:19:25 +01:00
|
|
|
/* add to allocator */
|
2013-02-21 13:45:39 +01:00
|
|
|
allocator().add_range(base, BACKING_STORE_SIZE);
|
2015-03-26 13:47:14 +01:00
|
|
|
} catch (...) { return false; }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-02-21 13:45:39 +01:00
|
|
|
return true;
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-26 13:47:14 +01:00
|
|
|
|
|
|
|
extern "C" void *dde_dma_alloc(dde_size_t size, dde_size_t align,
|
|
|
|
dde_size_t offset)
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
|
|
|
void *ptr;
|
2015-03-26 13:47:14 +01:00
|
|
|
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);
|
2012-11-28 22:50:08 +01:00
|
|
|
return 0;
|
2013-02-21 13:45:39 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-26 13:47:14 +01:00
|
|
|
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 **
|
|
|
|
**************/
|
|
|
|
|
2015-04-10 12:43:29 +02:00
|
|
|
static Genode::Io_port_session_client *_io_port;
|
2015-03-26 13:47:14 +01:00
|
|
|
|
2015-04-10 12:43:29 +02:00
|
|
|
extern "C" void dde_request_io(dde_uint8_t virt_bar_ioport)
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2015-03-26 13:47:14 +01:00
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
if (_io_port) {
|
|
|
|
PERR("Io_port_connection already open");
|
|
|
|
sleep_forever();
|
|
|
|
}
|
|
|
|
|
2015-04-10 12:43:29 +02:00
|
|
|
Pci::Device_client device(pci_drv()._cap);
|
|
|
|
Io_port_session_capability cap = device.io_port(virt_bar_ioport);
|
|
|
|
|
|
|
|
_io_port = new (env()->heap()) Io_port_session_client(cap);
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-26 13:47:14 +01:00
|
|
|
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); }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-03-26 13:47:14 +01:00
|
|
|
|
|
|
|
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
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
|
|
|
/*
|
2015-03-26 13:47:14 +01:00
|
|
|
* 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
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
2015-03-26 13:47:14 +01:00
|
|
|
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
|
|
|
|
{
|
2015-04-12 13:00:34 +02:00
|
|
|
Genode::Io_mem_session_client _mem;
|
2015-03-26 13:47:14 +01:00
|
|
|
Genode::Io_mem_dataspace_capability _mem_ds;
|
|
|
|
|
|
|
|
Genode::addr_t _vaddr;
|
|
|
|
|
2015-04-12 13:00:34 +02:00
|
|
|
Io_memory(Genode::addr_t base, Genode::Io_mem_session_capability cap)
|
2015-03-26 13:47:14 +01:00
|
|
|
:
|
2015-04-12 13:00:34 +02:00
|
|
|
_mem(cap),
|
2015-03-26 13:47:14 +01:00
|
|
|
_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;
|
|
|
|
|
|
|
|
|
2015-04-12 13:00:34 +02:00
|
|
|
extern "C" int dde_request_iomem(dde_addr_t start, dde_addr_t *vaddr)
|
2015-03-26 13:47:14 +01:00
|
|
|
{
|
|
|
|
if (_io_mem) {
|
|
|
|
PERR("Io_memory already requested");
|
|
|
|
Genode::sleep_forever();
|
|
|
|
}
|
|
|
|
|
2015-04-12 13:00:34 +02:00
|
|
|
Pci::Device_client device(pci_drv()._cap);
|
|
|
|
Genode::Io_mem_session_capability cap;
|
|
|
|
|
|
|
|
Genode::uint8_t virt_iomem_bar = 0;
|
|
|
|
for (unsigned i = 0; i < Pci::Device::NUM_RESOURCES; i++) {
|
|
|
|
Pci::Device::Resource res = device.resource(i);
|
|
|
|
if (res.type() == Pci::Device::Resource::MEMORY) {
|
|
|
|
if (res.base() == start) {
|
|
|
|
cap = device.io_mem(virt_iomem_bar);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
virt_iomem_bar ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!cap.valid())
|
|
|
|
return -1;
|
|
|
|
|
2015-03-26 13:47:14 +01:00
|
|
|
try {
|
2015-04-12 13:00:34 +02:00
|
|
|
_io_mem = new (Genode::env()->heap()) Io_memory(start, cap);
|
2015-03-26 13:47:14 +01:00
|
|
|
} 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; }
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|