lx_kit: add modular lx_emul backend

The modular lx_kit seperates the required back end functionality of the
Linux emulation environment from the front end. Thereby each driver can
reuse specific parts or supply more suitable implementations by itself.
It is used to reduce the amount of redundant code in each driver.

The lx_kit is split into several layers whose structure is as follows:

The first layer in _repos/dde_linux/src/include/lx_emul_ contains those
header files that provide the structural definitions and function
declarations of the Linux API, e.g. _errno.h_ provides all error code
values. The second layer in _repos/dde_linux/src/include/lx_emul/impl_
contains the implementation of selected functions, e.g. _slab.h_
provides the implementation of 'kmalloc()'. The lx_kit back end API is
the third layer and provides the _Lx::Malloc_ interface
(_repos/dde_linux/src/include/lx_kit/malloc.h_) which is used to
implement 'kmalloc()'. There are several generic implementations of the
lx_kit interfaces that can be used by a driver.

A driver typically includes a 'lx_emul/impl/xyz.h' header once
directly in its lx_emul compilation unit. The lx_kit interface files
are only included in those compilation units that use or implement the
interface. If a driver wants to use a generic implementation it must
add the source file to its source file list. The generic
implementations are located in _repos/dde_linux/src/lx_kit/_.

The modular lx_kit still depends on the private _lx_emul.h_ header file
that is tailored to each driver. Since the lx_kit already contains much
of the declarations and definitions that were originally placed in
these private header files, those files can now ommit a large amount
of code.

Fixes #1974.
This commit is contained in:
Josef Söntgen 2016-03-17 15:19:03 +01:00 committed by Christian Helmuth
parent ee05fb9259
commit 0106045bad
77 changed files with 2608 additions and 1186 deletions

View File

@ -251,3 +251,35 @@ address is not fixed and may change every time the same device is plugged in.
The configuration of the USB driver can be changed at runtime to satisfy
dynamic configurations or rather policies when using the 'Usb' session
interface.
lx_kit
######
The modular lx_kit seperates the required back end functionality of the Linux
emulation environment from the front end. Thereby each driver can reuse
specific parts or supply more suitable implementations by itself. It is used to
reduce the amount of redundant code in each driver.
The lx_kit is split into several layers whose structure is as follows:
The first layer in _repos/dde_linux/src/include/lx_emul_ contains those header
files that provide the structural definitions and function declarations of the
Linux API, e.g. _errno.h_ provides all error code values. The second layer in
_repos/dde_linux/src/include/lx_emul/impl_ contains the implementation of
selected functions, e.g. _slab.h_ provides the implementation of 'kmalloc()'.
The lx_kit back end API is the third layer and provides the _Lx::Malloc_
interface (_repos/dde_linux/src/include/lx_kit/malloc.h_) which is used to
implement 'kmalloc()'. There are several generic implementations of the lx_kit
interfaces that can be used by a driver.
A driver typically includes a 'lx_emul/impl/xyz.h' header once directly in its
lx_emul compilation unit. The lx_kit interface files are only included in those
compilation units that use or implement the interface. If a driver wants to use
a generic implementation it must add the source file to its source file list.
The generic implementations are located in _repos/dde_linux/src/lx_kit/_.
The modular lx_kit still depends on the private _lx_emul.h_ header file that is
tailored to each driver. Since the lx_kit already contains much of the
declarations and definitions that were originally placed in these private
header files, those files can now ommit a large amount of code.

View File

@ -1,26 +0,0 @@
/*
* \brief Include before including Linux headers in C++
* \author Christian Helmuth
* \date 2014-08-21
*/
/*
* Copyright (C) 2014 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.
*/
#define extern_c_begin
extern "C" {
/* some warnings should only be switched of for Linux headers */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpointer-arith"
#pragma GCC diagnostic ignored "-Wsign-compare"
/* deal with C++ keywords used for identifiers etc. */
#define private private_
#define class class_
#define new new_

View File

@ -1,20 +0,0 @@
/*
* \brief Include after including Linux headers in C++
* \author Christian Helmuth
* \date 2014-08-21
*/
/*
* Copyright (C) 2014 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.
*/
#undef new
#undef class
#undef private
#pragma GCC diagnostic pop
} /* extern "C" */

View File

@ -1,102 +0,0 @@
/*
* \brief Slightly improved list
* \author Christian Helmuth
* \date 2014-09-25
*/
/*
* Copyright (C) 2014 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 _LIST_H_
#define _LIST_H_
#include <util/list.h>
namespace Lx {
template <typename> class List;
template <typename> class List_element;
}
template <typename LT>
class Lx::List : private Genode::List<LT>
{
private:
typedef Genode::List<LT> Base;
public:
using Base::Element;
void append(LT const *le)
{
LT *at = nullptr;
for (LT *l = first(); l; l = l->next())
at = l;
Base::insert(le, at);
}
void prepend(LT const *le)
{
Base::insert(le);
}
void insert_before(LT const *le, LT const *at)
{
if (at == first()) {
prepend(le);
return;
} else if (!at) {
append(le);
return;
}
for (LT *l = first(); l; l = l->next())
if (l->next() == at)
at = l;
Base::insert(le, at);
}
/****************************
** Genode::List interface **
****************************/
LT *first() { return Base::first(); }
LT const *first() const { return Base::first(); }
void insert(LT const *le, LT const *at = 0)
{
Base::insert(le, at);
}
void remove(LT const *le)
{
Base::remove(le);
}
};
template <typename T>
class Lx::List_element : public Lx::List<List_element<T> >::Element
{
private:
T *_object;
public:
List_element(T *object) : _object(object) { }
T *object() const { return _object; }
};
#endif /* _LIST_H_ */

View File

@ -1,83 +0,0 @@
#ifndef _INCLUDE__LX__LX_H_
#define _INCLUDE__LX__LX_H_
#include <stdarg.h>
#include <base/fixed_stdint.h>
typedef genode_int8_t int8_t;
typedef genode_int16_t int16_t;
typedef genode_int32_t int32_t;
typedef genode_uint32_t uint32_t;
typedef genode_int64_t int64_t;
typedef genode_uint8_t uint8_t;
typedef genode_uint16_t uint16_t;
typedef genode_uint64_t uint64_t;
typedef __SIZE_TYPE__ size_t;
void lx_printf(char const *, ...) __attribute__((format(printf, 1, 2)));
void lx_vprintf(char const *, va_list);
#define lx_log(doit, msg...) \
do { \
if (doit) { \
lx_printf("%s(): ", __func__); \
lx_printf(msg); \
lx_printf("\n"); \
} \
} while(0)
/**********************
** linux/compiler.h **
**********************/
#define __printf(a, b) __attribute__((format(printf, a, b)))
/**************************
** linux/compiler-gcc.h **
**************************/
#define __noreturn __attribute__((noreturn))
/***************
** asm/bug.h **
***************/
#define WARN_ON(condition) ({ \
int ret = !!(condition); \
if (ret) lx_printf("[%s] WARN_ON(" #condition ") ", __func__); \
ret; })
#define WARN(condition, fmt, arg...) ({ \
int ret = !!(condition); \
if (ret) lx_printf("[%s] *WARN* " fmt , __func__ , ##arg); \
ret; })
#define BUG() do { \
lx_printf("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
while (1); \
} while (0)
#define WARN_ON_ONCE WARN_ON
#define WARN_ONCE WARN
#define BUG_ON(condition) do { if (condition) BUG(); } while(0)
/********************
** linux/kernel.h **
********************/
static inline __printf(1, 2) void panic(const char *fmt, ...) __noreturn;
static inline void panic(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
lx_vprintf(fmt, args);
va_end(args);
lx_printf("panic()");
while (1) ;
}
#endif /* _INCLUDE__LX__LX_H_ */

View File

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

View File

@ -21,12 +21,12 @@
#define WARN_ON(condition) ({ \
int ret = !!(condition); \
if (ret) lx_printf("[%s] WARN_ON(" #condition ") ", __func__); \
if (ret) lx_printf("[%s] WARN_ON(" #condition ") \n", __func__); \
ret; })
#define WARN(condition, fmt, arg...) ({ \
int ret = !!(condition); \
if (ret) lx_printf("[%s] *WARN* " fmt , __func__ , ##arg); \
if (ret) lx_printf("[%s] *WARN* " fmt " \n", __func__ , ##arg); \
ret; })
#define BUG() do { \
@ -38,3 +38,9 @@
#define WARN_ONCE WARN
#define BUG_ON(condition) do { if (condition) BUG(); } while(0)
#define BUILD_BUG_ON_MSG(cond,msg) ({ \
extern int __attribute__((error(msg))) build_bug(); \
if (cond) { build_bug(); } })
#define BUILD_BUG() BUILD_BUG_ON_MSG(1,"BUILD_BUG failed")

View File

@ -45,7 +45,7 @@
#define __attribute_const__
#undef __always_inline
#define __always_inline
#define __always_inline inline
#undef __unused
#define noinline __attribute__((noinline))
@ -57,6 +57,13 @@
#define __noreturn __attribute__((noreturn))
#define WRITE_ONCE(x, val) \
({ \
barrier(); \
__builtin_memcpy((void *)&(x), (const void *)&(val), sizeof(x)); \
barrier(); \
})
/**************************
** linux/compiler-gcc.h **

View File

@ -0,0 +1,31 @@
/*
* \brief Linux kernel API
* \author Sebastian Sumpf
* \date 2016-03-31
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2016 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.
*/
/************************
** linux/completion.h **
************************/
struct completion;
void complete(struct completion *);
void init_completion(struct completion *c);
void wait_for_completion(struct completion *c);
unsigned long wait_for_completion_timeout(struct completion *c,
unsigned long timeout);
int wait_for_completion_interruptible(struct completion *c);
long wait_for_completion_interruptible_timeout(struct completion *c,
unsigned long timeout);

View File

@ -45,6 +45,7 @@ enum {
ENODEV = 19,
EINVAL = 22,
ENFILE = 23,
ENOTTY = 25,
EFBIG = 27,
ENOSPC = 28,
ESPIPE = 29,
@ -99,6 +100,7 @@ enum {
ENOTUNIQ = 207,
ERFKILL = 208,
ETIME = 209,
EPROBE_DEFER = 210,
MAX_ERRNO = 4095,
};

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
* Copyright (C) 2014-2016 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.
@ -23,8 +23,11 @@ extern "C" {
#pragma GCC diagnostic ignored "-Wsign-compare"
/* deal with C++ keywords used for identifiers etc. */
#define private private_
#define class class_
#define new new_
#define private private_
#define class class_
#define new new_
#define delete delete_
#define namespace namespace_
#define virtual virtual_
#endif /* __cplusplus */

View File

@ -13,9 +13,12 @@
#ifdef __cplusplus
#undef delete
#undef new
#undef class
#undef private
#undef namespace
#undef virtual
#pragma GCC diagnostic pop

View File

@ -45,13 +45,17 @@ enum {
__GFP_NO_KSWAPD = 0x00400000u,
__GFP_OTHER_NODE = 0x00800000u,
__GFP_WRITE = 0x01000000u,
__GFP_DIRECT_RECLAIM = 0x400000u,
__GFP_KSWAPD_RECLAIM = 0x2000000u,
GFP_LX_DMA = 0x80000000u,
__GFP_RECLAIM = __GFP_DIRECT_RECLAIM | __GFP_KSWAPD_RECLAIM,
GFP_ATOMIC = __GFP_HIGH,
GFP_DMA = __GFP_DMA,
GFP_DMA32 = __GFP_DMA32,
GFP_KERNEL = __GFP_WAIT | __GFP_IO | __GFP_FS,
GFP_TEMPORARY = __GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_RECLAIMABLE,
GFP_USER = __GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL,
GFP_HIGHUSER = __GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL |
__GFP_HIGHMEM,

View File

@ -5,12 +5,15 @@
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 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.
*/
/* Linux kint includes */
#include <lx_kit/internal/task.h>
typedef Lx::Task::List_element Wait_le;
typedef Lx::Task::List Wait_list;
@ -21,6 +24,16 @@ void init_waitqueue_head(wait_queue_head_t *wq)
}
void remove_wait_queue(wait_queue_head_t *wq, wait_queue_t *wait)
{
Wait_list *list = static_cast<Wait_list*>(wq->list);
if (!list)
return;
destroy(Genode::env()->heap(), list);
}
int waitqueue_active(wait_queue_head_t *wq)
{
Wait_list *list = static_cast<Wait_list*>(wq->list);
@ -59,8 +72,9 @@ void __wait_event(wait_queue_head_t wq)
{
Wait_list *list = static_cast<Wait_list *>(wq.list);
if (!list) {
PERR("__wait_event(): empty list in wq: %p", &wq);
Genode::sleep_forever();
PWRN("__wait_event():dd empty list in wq: %p", &wq);
init_waitqueue_head(&wq);
list = static_cast<Wait_list *>(wq.list);
}
Lx::Task *task = Lx::scheduler().current();
@ -80,20 +94,22 @@ void init_completion(struct completion *work)
void complete(struct completion *work)
{
work->done = 1;
Lx::Task *task = static_cast<Lx::Task*>(work->task);
if (task) { task->unblock(); }
}
unsigned long wait_for_completion_timeout(struct completion *work,
unsigned long timeout)
{
__wait_completion(work);
return 1;
return __wait_completion(work, timeout);
}
int wait_for_completion_interruptible(struct completion *work)
{
__wait_completion(work);
__wait_completion(work, 0);
return 0;
}
@ -101,12 +117,11 @@ int wait_for_completion_interruptible(struct completion *work)
long wait_for_completion_interruptible_timeout(struct completion *work,
unsigned long timeout)
{
__wait_completion(work);
return 1;
return __wait_completion(work, timeout);
}
void wait_for_completion(struct completion *work)
{
__wait_completion(work);
__wait_completion(work, 0);
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 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.
@ -14,7 +14,7 @@
/* Genode includes */
#include <timer_session/connection.h>
#include <lx_emul/impl/internal/timer.h>
#include <lx_kit/timer.h>
/*
* XXX We may consider to use the Lx::Timer instead of opening a dedicated

View File

@ -5,19 +5,21 @@
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 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 <lx_emul/impl/internal/addr_to_page_mapping.h>
#include <lx_emul/impl/internal/malloc.h>
/* Linux kit includes */
#include <lx_kit/addr_to_page_mapping.h>
#include <lx_kit/backend_alloc.h>
#include <lx_kit/malloc.h>
struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
{
struct page *page = (struct page *)kzalloc(sizeof(struct page) * 1<<order, 0);
struct page *page = (struct page *)kzalloc(sizeof(struct page), 0);
size_t size = PAGE_SIZE << order;
@ -33,12 +35,6 @@ struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
Lx::Addr_to_page_mapping::insert(page);
for (unsigned i = 0; i < 1UL<<order; i++) {
page[i].addr = (void*)((Genode::addr_t)page->addr + i*PAGE_SIZE);
page[i].paddr = page->paddr + i*PAGE_SIZE;
atomic_set(&page[i]._count, 1);
}
return page;
}

View File

@ -1,208 +0,0 @@
/*
* \brief Linux kernel memory allocator
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014 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 _LX_EMUL__IMPL__INTERNAL__MALLOC_H_
#define _LX_EMUL__IMPL__INTERNAL__MALLOC_H_
#include <lx_emul/impl/internal/slab_alloc.h>
#include <lx_emul/impl/internal/slab_backend_alloc.h>
namespace Lx { class Malloc; }
class Lx::Malloc
{
private:
enum {
SLAB_START_LOG2 = 3, /* 8 B */
SLAB_STOP_LOG2 = 16, /* 64 KiB */
NUM_SLABS = (SLAB_STOP_LOG2 - SLAB_START_LOG2) + 1,
};
typedef Genode::addr_t addr_t;
typedef Lx::Slab_alloc Slab_alloc;
typedef Lx::Slab_backend_alloc Slab_backend_alloc;
Slab_backend_alloc &_back_allocator;
Slab_alloc *_allocator[NUM_SLABS];
Genode::Cache_attribute _cached; /* cached or un-cached memory */
addr_t _start; /* VM region of this allocator */
addr_t _end;
/**
* Set 'value' at 'addr'
*/
void _set_at(addr_t addr, addr_t value) { *((addr_t *)addr) = value; }
/**
* Retrieve slab index belonging to given address
*/
unsigned _slab_index(Genode::addr_t **addr)
{
using namespace Genode;
/* get index */
addr_t index = *(*addr - 1);
/*
* If index large, we use aligned memory, retrieve beginning of slab entry
* and read index from there
*/
if (index > 32) {
*addr = (addr_t *)*(*addr - 1);
index = *(*addr - 1);
}
return index;
}
/**
* Get the originally requested size of the allocation
*/
size_t _get_orig_size(Genode::addr_t **addr)
{
using namespace Genode;
addr_t index = *(*addr - 1);
if (index > 32) {
*addr = (addr_t *) * (*addr - 1);
}
return *(*addr - 2);
}
public:
Malloc(Slab_backend_alloc &alloc, Genode::Cache_attribute cached)
:
_back_allocator(alloc), _cached(cached), _start(alloc.start()),
_end(alloc.end())
{
/* init slab allocators */
for (unsigned i = SLAB_START_LOG2; i <= SLAB_STOP_LOG2; i++)
_allocator[i - SLAB_START_LOG2] = new (Genode::env()->heap())
Slab_alloc(1U << i, alloc);
}
/**
* Alloc in slabs
*/
void *alloc(Genode::size_t size, int align = 0, Genode::addr_t *phys = 0)
{
using namespace Genode;
/* save requested size */
size_t orig_size = size;
size += sizeof(addr_t);
/* += slab index + aligment size */
size += sizeof(addr_t) + (align > 2 ? (1 << align) : 0);
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) {
PERR("Slab too large %u reqested %zu cached %d", 1U << msb, size, _cached);
return 0;
}
addr_t addr = _allocator[msb - SLAB_START_LOG2]->alloc();
if (!addr) {
PERR("Failed to get slab for %u", 1 << msb);
return 0;
}
_set_at(addr, orig_size);
addr += sizeof(addr_t);
_set_at(addr, msb - SLAB_START_LOG2);
addr += sizeof(addr_t);
if (align > 2) {
/* save */
addr_t ptr = addr;
addr_t align_val = (1U << align);
addr_t align_mask = align_val - 1;
/* align */
addr = (addr + align_val) & ~align_mask;
/* write start address before aligned address */
_set_at(addr - sizeof(addr_t), ptr);
}
if (phys)
*phys = _back_allocator.phys_addr(addr);
return (addr_t *)addr;
}
void free(void const *a)
{
using namespace Genode;
addr_t *addr = (addr_t *)a;
/* XXX changes addr */
unsigned nr = _slab_index(&addr);
/* we need to decrease addr by 2, orig_size and index come first */
_allocator[nr]->free((void *)(addr - 2));
}
size_t size(void const *a)
{
using namespace Genode;
addr_t *addr = (addr_t *)a;
/* XXX changes addr */
return _get_orig_size(&addr);
}
Genode::addr_t phys_addr(void *a)
{
return _back_allocator.phys_addr((addr_t)a);
}
Genode::addr_t virt_addr(Genode::addr_t phys)
{
return _back_allocator.virt_addr(phys);
}
/**
* Belongs given address to this allocator
*/
bool inside(addr_t const addr) const { return (addr > _start) && (addr <= _end); }
/**
* Cached memory allocator
*/
static Malloc & mem()
{
static Malloc inst(Slab_backend_alloc::mem(), Genode::CACHED);
return inst;
}
/**
* DMA memory allocator
*/
static Malloc & dma()
{
static Malloc inst(Slab_backend_alloc::dma(), Genode::UNCACHED);
return inst;
}
};
#endif /* _LX_EMUL__IMPL__INTERNAL__MALLOC_H_ */

View File

@ -1,175 +0,0 @@
/*
* \brief Back-end allocator for Genode's slab allocator
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014 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 _LX_EMUL__IMPL__INTERNAL__SLAB_BACKEND_ALLOC_H_
#define _LX_EMUL__IMPL__INTERNAL__SLAB_BACKEND_ALLOC_H_
/* Genode includes */
#include <base/env.h>
#include <base/allocator_avl.h>
#include <rm_session/connection.h>
#include <region_map/client.h>
#include <dataspace/client.h>
namespace Lx {
Genode::Ram_dataspace_capability
backend_alloc(Genode::addr_t size, Genode::Cache_attribute cached);
void backend_free(Genode::Ram_dataspace_capability cap);
class Slab_backend_alloc;
}
class Lx::Slab_backend_alloc : public Genode::Allocator,
public Genode::Rm_connection,
public Genode::Region_map_client
{
private:
typedef Genode::addr_t addr_t;
enum {
VM_SIZE = 24 * 1024 * 1024, /* size of VM region to reserve */
BLOCK_SIZE = 1024 * 1024, /* 1 MiB */
ELEMENTS = VM_SIZE / BLOCK_SIZE, /* MAX number of dataspaces in VM */
};
addr_t _base; /* virt. base address */
Genode::Cache_attribute _cached; /* non-/cached RAM */
Genode::Ram_dataspace_capability _ds_cap[ELEMENTS]; /* dataspaces to put in VM */
addr_t _ds_phys[ELEMENTS]; /* physical bases of dataspaces */
int _index; /* current index in ds_cap */
Genode::Allocator_avl _range; /* manage allocations */
bool _alloc_block()
{
if (_index == ELEMENTS) {
PERR("Slab-backend exhausted!");
return false;
}
try {
_ds_cap[_index] = Lx::backend_alloc(BLOCK_SIZE, _cached);
/* attach at index * BLOCK_SIZE */
Region_map_client::attach_at(_ds_cap[_index], _index * BLOCK_SIZE, BLOCK_SIZE, 0);
/* lookup phys. address */
_ds_phys[_index] = Genode::Dataspace_client(_ds_cap[_index]).phys_addr();
} catch (...) { return false; }
/* return base + offset in VM area */
addr_t block_base = _base + (_index * BLOCK_SIZE);
++_index;
_range.add_range(block_base, BLOCK_SIZE);
return true;
}
public:
Slab_backend_alloc(Genode::Cache_attribute cached)
:
Region_map_client(Rm_connection::create(VM_SIZE)),
_cached(cached), _index(0), _range(Genode::env()->heap())
{
/* reserver attach us, anywere */
_base = Genode::env()->rm_session()->attach(dataspace());
}
/**
* Allocate
*/
bool alloc(size_t size, void **out_addr) override
{
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, size_t size) override { _range.free(addr, size); }
size_t overhead(size_t size) const override { return 0; }
bool need_size_for_free() const override { return false; }
/**
* Return phys address for given virtual addr.
*/
addr_t phys_addr(addr_t addr)
{
if (addr < _base || addr >= (_base + VM_SIZE))
return ~0UL;
int index = (addr - _base) / BLOCK_SIZE;
/* physical base of dataspace */
addr_t phys = _ds_phys[index];
if (!phys)
return ~0UL;
/* add offset */
phys += (addr - _base - (index * BLOCK_SIZE));
return phys;
}
/**
* Translate given physical address to virtual address
*
* \return virtual address, or 0 if no translation exists
*/
addr_t virt_addr(addr_t phys)
{
for (unsigned i = 0; i < ELEMENTS; i++) {
if (_ds_cap[i].valid() &&
phys >= _ds_phys[i] && phys < _ds_phys[i] + BLOCK_SIZE)
return _base + i*BLOCK_SIZE + phys - _ds_phys[i];
}
PWRN("virt_addr(0x%lx) - no translation", phys);
return 0;
}
addr_t start() const { return _base; }
addr_t end() const { return _base + VM_SIZE - 1; }
/**
* Cached memory backend allocator
*/
static Slab_backend_alloc & mem()
{
static Slab_backend_alloc inst(Genode::CACHED);
return inst;
}
/**
* DMA memory backend allocator
*/
static Slab_backend_alloc & dma()
{
static Slab_backend_alloc inst(Genode::UNCACHED);
return inst;
}
};
#endif /* _LX_EMUL__IMPL__INTERNAL__SLAB_BACKEND_ALLOC_H_ */

View File

@ -5,14 +5,15 @@
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 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 <lx_emul/impl/internal/pci_dev_registry.h>
#include <lx_emul/impl/internal/mapped_io_mem_range.h>
/* Linux kit includes */
#include <lx_kit/pci_dev_registry.h>
#include <lx_kit/mapped_io_mem_range.h>
void *ioremap(phys_addr_t phys_addr, unsigned long size)

View File

@ -5,13 +5,14 @@
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 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 <lx_emul/impl/internal/scheduler.h>
/* Linux kit includes */
#include <lx_kit/scheduler.h>
enum { MUTEX_UNLOCKED = 1, MUTEX_LOCKED = 0, MUTEX_WAITERS = -1 };
@ -24,6 +25,7 @@ void mutex_init(struct mutex *m)
m->holder = nullptr;
m->waiters = new (Genode::env()->heap()) Lx::Task::List;
m->id = ++id;
m->counter = 0;
}
@ -36,6 +38,7 @@ void mutex_destroy(struct mutex *m)
m->holder = nullptr;
m->waiters = nullptr;
m->id = 0;
m->counter = 0;
}
@ -52,8 +55,8 @@ void mutex_lock(struct mutex *m)
Lx::Task *t = reinterpret_cast<Lx::Task *>(m->holder);
if (t == Lx::scheduler().current()) {
PERR("Bug: mutex does not support recursive locking");
Genode::sleep_forever();
m->counter++;
return;
}
/* notice that a task waits for the mutex to be released */
@ -77,6 +80,11 @@ void mutex_unlock(struct mutex *m)
Genode::sleep_forever();
}
if (m->counter) {
m->counter--;
return;
}
Lx::Task::List *waiters = static_cast<Lx::Task::List *>(m->waiters);
if (m->state == MUTEX_WAITERS)

View File

@ -5,22 +5,17 @@
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 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 <io_mem_session/connection.h>
/* Linux kit includes */
#include <lx_kit/pci_dev_registry.h>
#include <lx_kit/mapped_io_mem_range.h>
#include <lx_emul/impl/internal/pci_dev_registry.h>
#include <lx_emul/impl/internal/mapped_io_mem_range.h>
extern void pci_dev_put(struct pci_dev *pci_dev)
{
Genode::destroy(Genode::env()->heap(), pci_dev);
}
#include <lx_emul/impl/pci_resource.h>
extern "C" int pci_register_driver(struct pci_driver *driver)
@ -44,9 +39,10 @@ extern "C" int pci_register_driver(struct pci_driver *driver)
/* look if we find the device ID in the driver's 'id_table' */
pci_device_id const *matching_id = nullptr;
for (pci_device_id const *id = id_table; id->class_ != 0; id++)
for (pci_device_id const *id = id_table; id->device; id++) {
if (id->device == device_id)
matching_id = id;
}
/* skip device that is not handled by driver */
if (!matching_id)
@ -78,124 +74,3 @@ extern "C" int pci_register_driver(struct pci_driver *driver)
return pci_dev ? 0 : -ENODEV;
}
extern "C" size_t pci_resource_start(struct pci_dev *dev, unsigned bar)
{
if (bar >= DEVICE_COUNT_RESOURCE)
return 0;
return dev->resource[bar].start;
}
extern "C" size_t pci_resource_end(struct pci_dev *dev, unsigned bar)
{
if (bar >= DEVICE_COUNT_RESOURCE)
return 0;
return dev->resource[bar].end;
}
extern "C" size_t pci_resource_len(struct pci_dev *dev, unsigned bar)
{
size_t start = pci_resource_start(dev, bar);
if (!start)
return 0;
return (dev->resource[bar].end - start) + 1;
}
extern "C" void *pci_ioremap_bar(struct pci_dev *dev, int bar)
{
using namespace Genode;
if (bar >= DEVICE_COUNT_RESOURCE || bar < 0)
return 0;
return Lx::ioremap(pci_resource_start(dev, bar),
pci_resource_len(dev, bar),
Genode::UNCACHED);
}
extern "C" unsigned int pci_resource_flags(struct pci_dev *dev, unsigned bar)
{
if (bar >= DEVICE_COUNT_RESOURCE)
return 0;
return dev->resource[bar].flags;
}
extern "C" int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int, int where, u8 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_read(where, val);
return 0;
}
extern "C" int pci_bus_read_config_word(struct pci_bus *bus, unsigned int, int where, u16 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_read(where, val);
return 0;
}
extern "C" int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int, int where, u32 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_read(where, val);
return 0;
}
extern "C" int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int, int where, u8 val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_write(where, val);
return 0;
}
extern "C" int pci_bus_write_config_word(struct pci_bus *bus, unsigned int, int where, u16 val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_write(where, val);
return 0;
}
extern "C" int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int, int where, u32 val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_write(where, val);
return 0;
}
extern "C" const char *pci_name(const struct pci_dev *pdev)
{
/* simply return driver name */
return "dummy";
}
extern "C" int pcie_capability_read_word(struct pci_dev *pdev, int pos, u16 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)pdev->bus;
switch (pos) {
case PCI_EXP_LNKCTL:
dev->config_read(pdev->pcie_cap + PCI_EXP_LNKCTL, val);
return 0;
break;
default:
break;
}
return 1;
}
//

View File

@ -0,0 +1,142 @@
/*
* \brief Implementation of linux/pci.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015-2016 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.
*/
/* Linux kit includes */
#include <lx_kit/pci_dev_registry.h>
#include <lx_kit/mapped_io_mem_range.h>
extern void pci_dev_put(struct pci_dev *pci_dev)
{
Genode::destroy(Genode::env()->heap(), pci_dev);
}
extern "C" size_t pci_resource_start(struct pci_dev *dev, unsigned bar)
{
if (bar >= DEVICE_COUNT_RESOURCE)
return 0;
return dev->resource[bar].start;
}
extern "C" size_t pci_resource_end(struct pci_dev *dev, unsigned bar)
{
if (bar >= DEVICE_COUNT_RESOURCE)
return 0;
return dev->resource[bar].end;
}
extern "C" size_t pci_resource_len(struct pci_dev *dev, unsigned bar)
{
size_t start = pci_resource_start(dev, bar);
if (!start)
return 0;
return (dev->resource[bar].end - start) + 1;
}
extern "C" void *pci_ioremap_bar(struct pci_dev *dev, int bar)
{
using namespace Genode;
if (bar >= DEVICE_COUNT_RESOURCE || bar < 0)
return 0;
return Lx::ioremap(pci_resource_start(dev, bar),
pci_resource_len(dev, bar),
Genode::UNCACHED);
}
extern "C" unsigned int pci_resource_flags(struct pci_dev *dev, unsigned bar)
{
if (bar >= DEVICE_COUNT_RESOURCE)
return 0;
return dev->resource[bar].flags;
}
extern "C" int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int, int where, u8 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_read(where, val);
return 0;
}
extern "C" int pci_bus_read_config_word(struct pci_bus *bus, unsigned int, int where, u16 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_read(where, val);
return 0;
}
extern "C" int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int, int where, u32 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_read(where, val);
return 0;
}
extern "C" int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int, int where, u8 val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_write(where, val);
return 0;
}
extern "C" int pci_bus_write_config_word(struct pci_bus *bus, unsigned int, int where, u16 val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_write(where, val);
return 0;
}
extern "C" int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int, int where, u32 val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_write(where, val);
return 0;
}
extern "C" const char *pci_name(const struct pci_dev *pdev)
{
/* simply return driver name */
return "dummy";
}
extern "C" int pcie_capability_read_word(struct pci_dev *pdev, int pos, u16 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)pdev->bus;
switch (pos) {
case PCI_EXP_LNKCTL:
dev->config_read(pdev->pcie_cap + PCI_EXP_LNKCTL, val);
return 0;
break;
default:
break;
}
return 1;
}

View File

@ -5,13 +5,14 @@
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 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 <lx_emul/impl/internal/scheduler.h>
/* Linux kit includes */
#include <lx_kit/scheduler.h>
static void unblock_task(unsigned long task)

View File

@ -5,13 +5,14 @@
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 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 <lx_emul/impl/internal/malloc.h>
/* Linux kit includes */
#include <lx_kit/malloc.h>
void *kmalloc(size_t size, gfp_t flags)
@ -21,8 +22,15 @@ void *kmalloc(size_t size, gfp_t flags)
if (flags & __GFP_DMA32)
PWRN("GFP_DMA32 memory (below 4 GiB) requested (%p)", __builtin_return_address(0));
void *addr = flags & GFP_LX_DMA ? Lx::Malloc::dma().alloc(size, 12)
: Lx::Malloc::mem().alloc(size);
void *addr = nullptr;
if (flags & GFP_LX_DMA) {
addr = Lx::Malloc::dma().alloc(size, 12);
} else {
addr = (size > (1 << Lx::Malloc::MAX_SIZE_LOG2))
? Lx::Malloc::mem().alloc_large(size)
: Lx::Malloc::mem().alloc(size);
}
if ((Genode::addr_t)addr & 0x3)
PERR("unaligned kmalloc %lx", (Genode::addr_t)addr);
@ -137,35 +145,39 @@ void *kmemdup(const void *src, size_t size, gfp_t flags)
struct kmem_cache : Lx::Slab_alloc
{
kmem_cache(size_t object_size, bool dma)
size_t _object_size;
void (*ctor)(void *);
kmem_cache(size_t object_size, bool dma, void (*ctor)(void *))
:
Lx::Slab_alloc(object_size, dma ? Lx::Slab_backend_alloc::dma()
: Lx::Slab_backend_alloc::mem())
: Lx::Slab_backend_alloc::mem()),
_object_size(object_size),
ctor(ctor)
{ }
size_t size() const { return _object_size; }
};
struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align,
unsigned long flags, void (*ctor)(void *))
{
if (ctor) {
PERR("%s: ctor not supported", __func__);
return nullptr;
}
/*
* Copied from wifi_drv.
*
* XXX SLAB_LX_DMA is never used anywhere else, remove it?
*/
enum { SLAB_LX_DMA = 0x80000000ul, };
return new (Genode::env()->heap()) kmem_cache(size, flags & SLAB_LX_DMA);
return new (Genode::env()->heap()) kmem_cache(size, flags & SLAB_LX_DMA, ctor);
}
void * kmem_cache_alloc(struct kmem_cache *cache, gfp_t flags)
{
return (void *)cache->alloc();
void *addr = (void *)cache->alloc();
if (addr && cache->ctor) { cache->ctor(addr); }
return addr;
}

View File

@ -5,13 +5,14 @@
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 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 <lx_emul/impl/internal/timer.h>
/* Linux kit includes */
#include <lx_kit/timer.h>
void init_timer(struct timer_list *timer) { }
@ -20,7 +21,7 @@ void init_timer(struct timer_list *timer) { }
int mod_timer(struct timer_list *timer, unsigned long expires)
{
if (!Lx::timer().find(timer))
Lx::timer().add(timer);
Lx::timer().add(timer, Lx::Timer::LIST);
return Lx::timer().schedule(timer, expires);
}
@ -50,3 +51,27 @@ int del_timer(struct timer_list *timer)
return rv;
}
void hrtimer_init(struct hrtimer *timer, clockid_t clock_id, enum hrtimer_mode mode) { }
int hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
unsigned long delta_ns, const enum hrtimer_mode mode)
{
unsigned long expires = tim.tv64 / (NSEC_PER_MSEC * HZ);
if (!Lx::timer().find(timer))
Lx::timer().add(timer, Lx::Timer::HR);
return Lx::timer().schedule(timer, expires);
}
int hrtimer_cancel(struct hrtimer *timer)
{
int rv = Lx::timer().del(timer);
Lx::timer().schedule_next();
return rv;
}

View File

@ -5,12 +5,16 @@
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 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.
*/
/* Linux kit includes */
#include <lx_kit/scheduler.h>
void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *w, int state)
{
if (!q) {

View File

@ -5,37 +5,69 @@
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 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 <lx_emul/impl/internal/work.h>
/* Linux kit includes */
#include <lx_kit/scheduler.h>
#include <lx_kit/work.h>
int schedule_work(struct work_struct *work)
{
Lx::Work::work_queue().schedule(work);
Lx::Work::work_queue().unblock();
queue_work(work->wq ? work->wq : system_wq, work);
return 1;
}
bool queue_work(struct workqueue_struct *wq, struct work_struct *work)
{
work->wq = wq;
/* check for separate work queue task */
if (wq && wq->task) {
Lx::Work *lx_work = (Lx::Work *)wq->task;
lx_work->schedule(work);
lx_work->unblock();
} else {
Lx::Work::work_queue().schedule(work);
Lx::Work::work_queue().unblock();
}
return true;
}
static void _schedule_delayed_work(unsigned long w)
{
schedule_work((struct work_struct *)w);
delayed_work *work = (delayed_work *)w;
workqueue_struct *wq = work->wq;
/* check for separate work queue task */
if (wq && wq->task) {
Lx::Work *lx_work = (Lx::Work *)wq->task;
lx_work->schedule_delayed(work, 0);
lx_work->unblock();
} else {
Lx::Work::work_queue().schedule_delayed(work, 0);
Lx::Work::work_queue().unblock();
}
}
bool queue_delayed_work(struct workqueue_struct *wq,
struct delayed_work *dwork, unsigned long delay)
{
dwork->wq = wq;
/* treat delayed work without delay like any other work */
if (delay == 0) {
schedule_work(&dwork->work);
_schedule_delayed_work((unsigned long)dwork);
} else {
setup_timer(&dwork->timer, _schedule_delayed_work, (unsigned long)&dwork->work);
setup_timer(&dwork->timer, _schedule_delayed_work, (unsigned long)dwork);
mod_timer(&dwork->timer, delay);
}
return true;
@ -44,7 +76,7 @@ bool queue_delayed_work(struct workqueue_struct *wq,
int schedule_delayed_work(struct delayed_work *dwork, unsigned long delay)
{
return queue_delayed_work(system_wq, dwork, delay);
return queue_delayed_work(dwork->wq ? dwork->wq : system_wq, dwork, delay);
}

View File

@ -20,6 +20,7 @@
*********************/
#define IS_ENABLED(x) x
#define IS_BUILTIN(x) x
/********************
@ -39,6 +40,12 @@
#define KERN_WARNING "WARNING: "
#define KERN_WARN "WARNING: "
struct va_format
{
const char *fmt;
va_list *va;
};
static inline int _printk(const char *fmt, ...)
{
va_list args;

View File

@ -24,13 +24,24 @@ struct kref { atomic_t refcount; };
void kref_init(struct kref *kref);
void kref_get(struct kref *kref);
int kref_put(struct kref *kref, void (*release) (struct kref *kref));
int kref_get_unless_zero(struct kref *kref);
int kref_put_mutex(struct kref *kref,
void (*release)(struct kref *kref),
struct mutex *lock);
/*********************
** linux/kobject.h **
*********************/
struct kobject { struct kobject *parent; };
struct kobject
{
struct kset *kset;
struct kobj_type *ktype;
struct kobject *parent;
const char *name;
};
struct kobj_uevent_env
{
char buf[32];

View File

@ -65,6 +65,8 @@ int try_module_get(struct module *);
#define module_param(name, type, perm)
#define module_param_named(name, value, type, perm)
#define module_param_unsafe(name, type, perm)
#define module_param_named_unsafe(name, value, type, perm)
#define MODULE_PARM_DESC(_parm, desc)
#define kparam_block_sysfs_write(name)
#define kparam_unblock_sysfs_write(name)

View File

@ -24,6 +24,7 @@ struct mutex
int state;
void *holder;
void *waiters;
unsigned counter;
unsigned id; /* for debugging */
};

View File

@ -51,8 +51,9 @@ struct pci_driver {
char *name;
const struct pci_device_id *id_table;
int (*probe) (struct pci_dev *dev,
const struct pci_device_id *id);
const struct pci_device_id *id);
void (*remove) (struct pci_dev *dev);
void (*shutdown) (struct pci_dev *dev);
struct device_driver driver;
};

View File

@ -23,7 +23,11 @@ struct device;
typedef struct pm_message { int event; } pm_message_t;
struct dev_pm_info { pm_message_t power_state; };
struct dev_pm_info
{
pm_message_t power_state;
bool is_prepared;
};
struct dev_pm_ops {
int (*suspend)(struct device *dev);
@ -34,10 +38,17 @@ struct dev_pm_ops {
int (*restore)(struct device *dev);
int (*runtime_suspend)(struct device *dev);
int (*runtime_resume)(struct device *dev);
int (*suspend_late)(struct device *dev);
int (*resume_early)(struct device *dev);
int (*freeze_late)(struct device *dev);
int (*thaw_early)(struct device *dev);
int (*poweroff_late)(struct device *dev);
int (*restore_early)(struct device *dev);
};
#define PMSG_IS_AUTO(msg) 0
enum { PM_EVENT_AUTO_SUSPEND = 0x402 };
#define PM_EVENT_FREEZE 0x0001
#define PM_EVENT_SUSPEND 0x0002

View File

@ -36,6 +36,7 @@ struct sg_table
{
struct scatterlist *sgl; /* the list */
unsigned int nents; /* number of mapped entries */
unsigned int orig_nents;
};
struct sg_page_iter
@ -56,6 +57,10 @@ struct sg_mapping_iter
struct page;
#define sg_is_chain(sg) ((sg)->page_link & 0x01)
#define sg_chain_ptr(sg) \
((struct scatterlist *) ((sg)->page_link & ~0x03))
void sg_init_table(struct scatterlist *, unsigned int);
void sg_set_buf(struct scatterlist *sg, const void *buf, unsigned int buflen);
void sg_set_page(struct scatterlist *sg, struct page *page,

View File

@ -41,4 +41,4 @@ int spin_trylock(spinlock_t *lock);
** linux/spinlock_types.h **
****************************/
#define __SPIN_LOCK_UNLOCKED(x) 0
#define __SPIN_LOCK_UNLOCKED(x) {0}

View File

@ -24,7 +24,12 @@ struct timespec {
long tv_nsec;
};
struct timeval { };
struct timeval
{
__kernel_time_t tv_sec;
__kernel_suseconds_t tv_usec;
};
struct timespec current_kernel_time(void);
void do_gettimeofday(struct timeval *tv);
@ -74,7 +79,13 @@ static inline ktime_t ktime_add(const ktime_t a, const ktime_t b)
s64 ktime_us_delta(const ktime_t later, const ktime_t earlier);
struct timeval ktime_to_timeval(const ktime_t);
static inline struct timeval ktime_to_timeval(const ktime_t kt)
{
struct timeval tv;
tv.tv_sec = kt.tv64 / NSEC_PER_SEC;
tv.tv_usec = (kt.tv64 - (tv.tv_sec * NSEC_PER_SEC)) / NSEC_PER_USEC;
return tv;
}
ktime_t ktime_get_real(void);
ktime_t ktime_sub(const ktime_t, const ktime_t);

View File

@ -48,3 +48,24 @@ static inline void add_timer(struct timer_list *timer) { mod_timer(timer, timer-
static inline
int del_timer_sync(struct timer_list * timer) { return del_timer(timer); }
/*********************
** linux/hrtimer.h **
*********************/
enum hrtimer_mode { HRTIMER_MODE_ABS = 0 };
enum hrtimer_restart { HRTIMER_NORESTART = 0 };
struct hrtimer
{
enum hrtimer_restart (*function)(struct hrtimer *);
struct hrtimer *data;
void *timer;
};
int hrtimer_start_range_ns(struct hrtimer *, ktime_t,
unsigned long, const enum hrtimer_mode);
void hrtimer_init(struct hrtimer *, clockid_t, enum hrtimer_mode);
int hrtimer_cancel(struct hrtimer *);

View File

@ -90,7 +90,9 @@ typedef u32 uid_t;
typedef u32 gid_t;
typedef unsigned kuid_t;
typedef unsigned kgid_t;
typedef size_t __kernel_size_t;
typedef long __kernel_time_t;
typedef long __kernel_suseconds_t;
typedef unsigned short umode_t;
typedef __u16 __be16;
typedef __u32 __be32;

View File

@ -31,11 +31,15 @@ struct work_struct {
atomic_long_t data;
work_func_t func;
struct list_head entry;
struct workqueue_struct *wq;
};
struct workqueue_struct { void *task; };
struct delayed_work {
struct timer_list timer;
struct work_struct work;
struct workqueue_struct *wq;
};
bool cancel_work_sync(struct work_struct *work);
@ -73,7 +77,6 @@ bool flush_work_sync(struct work_struct *work);
/* dummy for queue_delayed_work call in storage/usb.c */
#define system_freezable_wq 0
struct workqueue_struct { unsigned unused; };
struct workqueue_struct *create_singlethread_workqueue(const char *name);
struct workqueue_struct *alloc_ordered_workqueue(const char *fmt, unsigned int flags, ...) __printf(1, 3);
@ -135,8 +138,14 @@ enum {
** linux/wait.h **
******************/
typedef struct wait_queue wait_queue_t;
typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int flags, void *key);
typedef struct wait_queue_head { void *list; } wait_queue_head_t;
typedef struct wait_queue { unsigned unused; } wait_queue_t;
struct wait_queue
{
wait_queue_func_t func;
void *private;
};
#define DEFINE_WAIT(name) \
wait_queue_t name;

View File

@ -7,26 +7,26 @@
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
* Copyright (C) 2014-2016 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 _LX_EMUL__IMPL__INTERNAL__ADDR_TO_PAGE_MAPPING_H_
#define _LX_EMUL__IMPL__INTERNAL__ADDR_TO_PAGE_MAPPING_H_
#ifndef _LX_KIT__ADDR_TO_PAGE_MAPPING_H_
#define _LX_KIT__ADDR_TO_PAGE_MAPPING_H_
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/malloc.h>
#include <lx_emul/impl/internal/list.h>
#include <lx_kit/internal/list.h>
#include <lx_kit/malloc.h>
namespace Lx { class Addr_to_page_mapping; }
class Lx::Addr_to_page_mapping : public Lx::List<Addr_to_page_mapping>::Element
class Lx::Addr_to_page_mapping : public Lx_kit::List<Addr_to_page_mapping>::Element
{
private:
unsigned long _addr { 0 };
unsigned long _addr { 0 };
struct page *_page { 0 };
static Genode::List<Addr_to_page_mapping> *_list()
@ -75,4 +75,4 @@ class Lx::Addr_to_page_mapping : public Lx::List<Addr_to_page_mapping>::Element
};
#endif /* _LX_EMUL__IMPL__INTERNAL__ADDR_TO_PAGE_MAPPING_H_ */
#endif /* _LX_KIT__ADDR_TO_PAGE_MAPPING_H_ */

View File

@ -0,0 +1,33 @@
/*
* \brief Back-end allocator
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014-2016 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 _LX_KIT__BACKEND_ALLOC_H_
#define _LX_KIT__BACKEND_ALLOC_H_
/* Linux emulation environment includes */
#include <lx_kit/types.h>
namespace Lx {
using namespace Genode;
Ram_dataspace_capability backend_alloc(addr_t size,
Cache_attribute cached);
void backend_free(Ram_dataspace_capability cap);
}
#endif /* _LX_KIT__BACKEND_ALLOC_H_ */

View File

@ -7,17 +7,17 @@
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
* Copyright (C) 2014-2016 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 _LX_EMUL__IMPL__INTERNAL__DEBUG_H_
#define _LX_EMUL__IMPL__INTERNAL__DEBUG_H_
#ifndef _LX_KIT__INTERNAL__DEBUG_H_
#define _LX_KIT__INTERNAL__DEBUG_H_
#ifndef PDBGV
#define PDBGV(...) do { if (verbose) PDBG(__VA_ARGS__); } while (0)
#endif
#endif /* _LX_EMUL__IMPL__INTERNAL__DEBUG_H_ */
#endif /* _LX_KIT__INTERNAL__DEBUG_H_ */

View File

@ -6,14 +6,14 @@
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
* Copyright (C) 2014-2016 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 _LX_EMUL__IMPL__INTERNAL__IO_PORT_H_
#define _LX_EMUL__IMPL__INTERNAL__IO_PORT_H_
#ifndef _LX_KIT__INTERNAL__IO_PORT_H_
#define _LX_KIT__INTERNAL__IO_PORT_H_
/* Genode includes */
#include <util/volatile_object.h>
@ -68,7 +68,7 @@ class Lx::Io_port
bool in(unsigned port, POD *val)
{
if (!_valid(port))
return false;;
return false;
switch (sizeof(POD)) {
case 1: *val = _port->inb(port); break;
@ -80,4 +80,4 @@ class Lx::Io_port
}
};
#endif /* _LX_EMUL__IMPL__INTERNAL__IO_PORT_H_ */
#endif /* _LX_KIT__INTERNAL__IO_PORT_H_ */

View File

@ -5,25 +5,25 @@
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
* Copyright (C) 2014-2016 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 _LX_EMUL__IMPL__INTERNAL__LIST_H_
#define _LX_EMUL__IMPL__INTERNAL__LIST_H_
#ifndef _LX_KIT__INTERNAL__LIST_H_
#define _LX_KIT__INTERNAL__LIST_H_
#include <util/list.h>
namespace Lx {
namespace Lx_kit {
template <typename> class List;
template <typename> class List_element;
}
template <typename LT>
class Lx::List : private Genode::List<LT>
class Lx_kit::List : private Genode::List<LT>
{
private:
@ -86,7 +86,7 @@ class Lx::List : private Genode::List<LT>
template <typename T>
class Lx::List_element : public Lx::List<List_element<T> >::Element
class Lx_kit::List_element : public Lx_kit::List<List_element<T> >::Element
{
private:
@ -99,4 +99,4 @@ class Lx::List_element : public Lx::List<List_element<T> >::Element
T *object() const { return _object; }
};
#endif /* _LX_EMUL__IMPL__INTERNAL__LIST_H_ */
#endif /* _LX_KIT__INTERNAL__LIST_H_ */

View File

@ -13,8 +13,8 @@
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__PCI_DEV_H_
#define _LX_EMUL__IMPL__INTERNAL__PCI_DEV_H_
#ifndef _LX_KIT__INTERNAL__PCI_DEV_H_
#define _LX_KIT__INTERNAL__PCI_DEV_H_
/* Genode includes */
#include <base/object_pool.h>
@ -25,9 +25,9 @@
#include <util/retry.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/debug.h>
#include <lx_emul/impl/internal/list.h>
#include <lx_emul/impl/internal/io_port.h>
#include <lx_kit/internal/debug.h>
#include <lx_kit/internal/list.h>
#include <lx_kit/internal/io_port.h>
namespace Lx {
@ -45,7 +45,7 @@ namespace Lx {
}
class Lx::Pci_dev : public pci_dev, public Lx::List<Pci_dev>::Element
class Lx::Pci_dev : public pci_dev, public Lx_kit::List<Pci_dev>::Element
{
private:
@ -76,6 +76,12 @@ class Lx::Pci_dev : public pci_dev, public Lx::List<Pci_dev>::Element
}
}
static unsigned _virq_num()
{
static unsigned instance = 128;
return ++instance;
}
public:
/**
@ -99,8 +105,18 @@ class Lx::Pci_dev : public pci_dev, public Lx::List<Pci_dev>::Element
this->dev.dma_mask = &this->dev._dma_mask_buf;
this->dev.coherent_dma_mask = ~0;
/* read interrupt line */
this->irq = _client.config_read(IRQ, Device::ACCESS_8BIT);
enum { USB_SUB_CLASS = 0xc0300 };
/*
* For USB we generate virtual IRQ numbers so we can identify the device
* later on
*/
if ((class_ & ~0xffU) == USB_SUB_CLASS)
this->irq = _virq_num();
else
/* read interrupt line */
this->irq = _client.config_read(IRQ, Device::ACCESS_8BIT);
/* hide ourselfs in bus structure */
this->bus = (struct pci_bus *)this;
@ -261,4 +277,4 @@ void Lx::for_each_pci_device(FUNC const &func)
}
}
#endif /* _LX_EMUL__IMPL__INTERNAL__PCI_DEV_H_ */
#endif /* _LX_KIT__INTERNAL__PCI_DEV_H_ */

View File

@ -13,15 +13,16 @@
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__SLAB_ALLOC_H_
#define _LX_EMUL__IMPL__INTERNAL__SLAB_ALLOC_H_
#ifndef _LX_KIT__INTERAL__SLAB_ALLOC_H_
#define _LX_KIT__INTERAL__SLAB_ALLOC_H_
/* Genode includes */
#include <base/slab.h>
#include <util/misc_math.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/slab_backend_alloc.h>
#include <lx_kit/internal/slab_backend_alloc.h>
#include <lx_kit/types.h>
namespace Lx { class Slab_alloc; }
@ -50,9 +51,6 @@ class Lx::Slab_alloc : public Genode::Slab
_object_size(object_size)
{ }
/**
* Convenience slabe-entry allocation
*/
Genode::addr_t alloc()
{
Genode::addr_t result;
@ -65,4 +63,4 @@ class Lx::Slab_alloc : public Genode::Slab
}
};
#endif /* _LX_EMUL__IMPL__INTERNAL__SLAB_ALLOC_H_ */
#endif /* _LX_KIT__INTERAL__SLAB_ALLOC_H_ */

View File

@ -0,0 +1,64 @@
/*
* \brief Back-end allocator for Genode's slab allocator
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014 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 _LX_KIT__INTERAL__SLAB_BACKEND_ALLOC_H_
#define _LX_KIT__INTERAL__SLAB_BACKEND_ALLOC_H_
/* Genode includes */
#include <base/allocator_avl.h>
/* Linux emulation environment includes */
#include <lx_kit/types.h>
namespace Lx {
using Lx_kit::addr_t;
class Slab_backend_alloc;
}
class Lx::Slab_backend_alloc : public Genode::Allocator
{
public:
/**
* Allocate
*/
virtual bool alloc(size_t size, void **out_addr) = 0;
virtual void free(void *addr) = 0;
/**
* Return phys address for given virtual addr.
*/
virtual addr_t phys_addr(addr_t addr) = 0;
/**
* Translate given physical address to virtual address
*
* \return virtual address, or 0 if no translation exists
*/
virtual addr_t virt_addr(addr_t phys) = 0;
virtual addr_t start() const = 0;
virtual addr_t end() const = 0;
static Slab_backend_alloc &mem();
static Slab_backend_alloc &dma();
};
#endif /* _LX_KIT__INTERAL__SLAB_BACKEND_ALLOC_H_ */

View File

@ -13,29 +13,33 @@
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__TASK_H_
#define _LX_EMUL__IMPL__INTERNAL__TASK_H_
/* libc includes */
#include <setjmp.h>
#ifndef _LX_KIT__INTERNAL__TASK_H_
#define _LX_KIT__INTERNAL__TASK_H_
/* Genode includes */
#include <base/printf.h>
#include <base/thread.h>
#include <base/sleep.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/list.h>
#include <lx_emul/impl/internal/arch_execute.h>
#include <lx_kit/internal/list.h>
#include <lx_kit/internal/arch_execute.h>
#if !defined(USE_INTERNAL_SETJMP)
/* libc includes */
#include <setjmp.h>
#endif /* USE_INTERNAL_SETJMP */
namespace Lx {
class Scheduler;
class Task;
}
/**
* Allows pseudo-parallel execution of functions
*/
class Lx::Task : public Lx::List<Lx::Task>::Element
class Lx::Task : public Lx_kit::List<Lx::Task>::Element
{
public:
@ -61,16 +65,16 @@ class Lx::Task : public Lx::List<Lx::Task>::Element
/**
* List element type
*/
typedef Lx::List_element<Lx::Task> List_element;
typedef Lx_kit::List_element<Lx::Task> List_element;
/**
* List type
*/
typedef Lx::List<List_element> List;
typedef Lx_kit::List<List_element> List;
private:
bool verbose = true;
bool verbose = false;
State _state = STATE_INIT;
@ -106,16 +110,14 @@ class Lx::Task : public Lx::List<Lx::Task>::Element
List_element _wait_le { this };
bool _wait_le_enqueued { false };
inline void _deinit();
public:
inline Task(void (*func)(void*), void *arg, char const *name,
Priority priority, Scheduler &scheduler);
Task(void (*func)(void*), void *arg, char const *name,
Priority priority, Scheduler &scheduler);
virtual ~Task() { _deinit(); }
virtual ~Task();
State state() const { return _state; }
State state() const { return _state; }
Priority priority() const { return _priority; }
void wait_enqueue(List *list)
@ -254,4 +256,5 @@ class Lx::Task : public Lx::List<Lx::Task>::Element
char const *name() { return _name; }
};
#endif /* _LX_EMUL__IMPL__INTERNAL__TASK_H_ */
#endif /* _LX_KIT__INTERNAL__TASK_H_ */

View File

@ -0,0 +1,40 @@
/*
* \brief Signal context for IRQ's
* \author Josef Soentgen
* \author Christian Helmuth
* \author Stefan Kalkowski
* \date 2014-10-14
*/
/*
* Copyright (C) 2014-2016 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 _LX_KIT__IRQ_H_
#define _LX_KIT__IRQ_H_
/* Genode includes */
#include <os/server.h>
#include <platform_device/platform_device.h>
namespace Lx { class Irq; }
class Lx::Irq
{
public:
static Irq &irq(Server::Entrypoint *ep = nullptr,
Genode::Allocator *alloc = nullptr);
/**
* Request an IRQ
*/
virtual void request_irq(Platform::Device &dev, irq_handler_t handler,
void *dev_id, irq_handler_t thread_fn = 0) = 0;
};
#endif /* _LX_KIT__IRQ_H_ */

View File

@ -0,0 +1,63 @@
/*
* \brief Linux kernel memory allocator
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014-2016 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 _LX_KIT__MALLOC_H_
#define _LX_KIT__MALLOC_H_
/* Linux emulation environment includes */
#include <lx_kit/types.h>
#include <lx_kit/internal/slab_alloc.h>
#include <lx_kit/internal/slab_backend_alloc.h>
namespace Lx {
class Malloc;
}
class Lx::Malloc
{
public:
enum { MAX_SIZE_LOG2 = 16 /* 64 KiB */ };
/**
* Alloc in slabs
*/
virtual void *alloc(Genode::size_t size, int align = 0, Genode::addr_t *phys = 0) = 0;
virtual void free(void const *a) = 0;
virtual void *alloc_large(size_t size) = 0;
virtual void free_large(void *ptr) = 0;
virtual size_t size(void const *a) = 0;
virtual Genode::addr_t phys_addr(void *a) = 0;
virtual Genode::addr_t virt_addr(Genode::addr_t phys) = 0;
/**
* Belongs given address to this allocator
*/
virtual bool inside(addr_t const addr) const = 0;
static Malloc &mem();
static Malloc &dma();
};
#endif /* _LX_KIT__MALLOC_H_ */

View File

@ -0,0 +1,33 @@
/*
* \brief Representation of a locally-mapped MMIO range
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 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 _LX_KIT__MAPPED_IO_MEM_RANGE_H_
#define _LX_KIT__MAPPED_IO_MEM_RANGE_H_
/* Genode includes */
#include <dataspace/capability.h>
/* Linux emulation environment includes */
#include <lx_kit/types.h>
namespace Lx {
using namespace Genode;
void *ioremap(addr_t, unsigned long, Cache_attribute);
void iounmap(volatile void*);
Dataspace_capability ioremap_lookup(addr_t, size_t);
}
#endif /* _LX_KIT__MAPPED_IO_MEM_RANGE_H_ */

View File

@ -11,11 +11,11 @@
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__PCI_DEV_REGISTRY_H_
#define _LX_EMUL__IMPL__INTERNAL__PCI_DEV_REGISTRY_H_
#ifndef _LX_KIT__PCI_DEV_REGISTRY_H_
#define _LX_KIT__PCI_DEV_REGISTRY_H_
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/pci_dev.h>
#include <lx_kit/internal/pci_dev.h>
namespace Lx {
@ -34,7 +34,7 @@ class Lx::Pci_dev_registry
{
private:
List<Pci_dev> _devs;
Lx_kit::List<Pci_dev> _devs;
public:
@ -44,7 +44,9 @@ class Lx::Pci_dev_registry
_devs.insert(pci_dev);
}
Genode::Io_mem_dataspace_capability io_mem(resource_size_t phys,
Pci_dev* first() { return _devs.first(); }
Genode::Io_mem_dataspace_capability io_mem(Genode::addr_t phys,
Genode::Cache_attribute cache_attribute,
Genode::size_t size,
Genode::addr_t &offset)
@ -72,7 +74,7 @@ class Lx::Pci_dev_registry
return Genode::Io_mem_session_client(io_mem_cap).dataspace();
}
PERR("Device using i/o memory of address %zx is unknown", phys);
PERR("Device using i/o memory of address %lx is unknown", phys);
return Genode::Io_mem_dataspace_capability();
}
@ -102,4 +104,4 @@ class Lx::Pci_dev_registry
}
};
#endif /* _LX_EMUL__IMPL__INTERNAL__PCI_DEV_REGISTRY_H_ */
#endif /* _LX_KIT__PCI_DEV_REGISTRY_H_ */

View File

@ -0,0 +1,75 @@
/*
* \brief Scheduler for executing Lx::Task objects
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014-2016 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 _LX_KIT__SCHEDULER_H_
#define _LX_KIT__SCHEDULER_H_
namespace Lx {
class Task;
class Scheduler;
/**
* Return singleton instance of the scheduler
*
* Implementation must be provided by the driver.
*/
Scheduler &scheduler();
}
class Lx::Scheduler
{
public:
/**
* Return currently scheduled task
*/
virtual Task *current() = 0;
/**
* Return true if a task is currently running
*/
virtual bool active() const = 0;
/**
* Add new task to the present list
*/
virtual void add(Task *task) = 0;
/**
* Remove a task
*/
virtual void remove(Task *task) = 0;
/**
* Schedule all present tasks
*
* Returns if no task is runnable.
*/
virtual void schedule() = 0;
/**
* Log current state of tasks in present list (debug)
*
* Log lines are prefixed with 'prefix'.
*/
virtual void log_state(char const *prefix) = 0;
};
#include <lx_kit/internal/task.h>
#endif /* _LX_KIT__SCHEDULER_H_ */

View File

@ -0,0 +1,84 @@
/*
* \brief Timer
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014-2016 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 _LX_KIT__TIMER_H_
#define _LX_KIT__TIMER_H_
/* Genode includes */
#include <os/server.h>
namespace Lx {
class Timer;
/**
* Return singleton instance of timer
*
* \param ep entrypoint used handle timeout signals,
* to be specified at the first call of the function,
* which implicitly initializes the timer
* \param jiffies_ptr pointer to jiffies counter to be periodically
* updated
*/
Timer &timer(Server::Entrypoint *ep = nullptr,
unsigned long *jiffies_ptr = nullptr);
void timer_update_jiffies();
}
class Lx::Timer
{
public:
enum Type { LIST, HR };
/**
* Add new linux timer
*/
virtual void add(void *timer, Type type) = 0;
/**
* Delete linux timer
*/
virtual int del(void *timer) = 0;
/**
* Initial scheduling of linux timer
*/
virtual int schedule(void *timer, unsigned long expires) = 0;
/**
* Schedule next linux timer
*/
virtual void schedule_next() = 0;
/**
* Check if the timer is currently pending
*/
virtual bool pending(void const *timer) = 0;
/**
* Check if the timer is already present
*/
virtual bool find(void const *timer) const = 0;
/**
* Update jiffie counter
*/
virtual void update_jiffies() = 0;
};
#endif /* _LX_KIT__TIMER_H_ */

View File

@ -0,0 +1,25 @@
/*
* \brief Linux kit types
* \author Josef Soentgen
* \date 2016-03-18
*/
/*
* Copyright (C) 2016 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 _LX_KIT__TYPES_H_
#define _LX_KIT__TYPES_H_
/* Genode includes */
#include <base/stdint.h>
namespace Lx_kit {
typedef Genode::size_t size_t;
typedef Genode::addr_t addr_t;
}
#endif /* _LX_KIT__TYPES_H_ */

View File

@ -0,0 +1,67 @@
/*
* \brief Work queue implementation
* \author Josef Soentgen
* \author Stefan Kalkowski
* \date 2015-10-26
*/
/*
* Copyright (C) 2015-2106 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 _LX_KIT__WORK_H_
#define _LX_KIT__WORK_H_
#include <base/allocator.h>
namespace Lx {
class Work;
}
class Lx::Work
{
public:
virtual ~Work() { }
/**
* Unblock corresponding task
*/
virtual void unblock() = 0;
/**
* Schedule work
*/
virtual void schedule(struct ::work_struct *) = 0;
/**
* Schedule delayed work
*/
virtual void schedule_delayed(struct ::delayed_work *, unsigned long delay) = 0;
/**
* Schedule delayed work
*/
virtual void schedule_tasklet(struct ::tasklet_struct *) = 0;
/**
* Cancel work item
*/
virtual bool cancel_work(struct ::work_struct *, bool sync = false) = 0;
/**
* Return task name
*/
virtual char const *task_name() = 0;
static Work &work_queue(Genode::Allocator *alloc = nullptr);
static Work *alloc_work_queue(Genode::Allocator *alloc, char const *name);
static void free_work_queue(Work *W);
};
#endif /* _LX_KIT__WORK_H_ */

View File

@ -0,0 +1,44 @@
/**
* \brief Platform specific code
* \author Sebastian Sumpf
* \date 2012-06-10
*/
/*
* Copyright (C) 2012-2016 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 _ARCH_EXECUTE_H_
#define _ARCH_EXECUTE_H_
#if defined(USE_INTERNAL_SETJMP)
#ifdef __cplusplus
extern "C" {
#endif
#define _JBLEN 64
typedef struct _jmp_buf { long _jb[_JBLEN + 1]; } jmp_buf[1];
void _longjmp(jmp_buf, int);
int _setjmp(jmp_buf);
#ifdef __cplusplus
}
#endif
#endif /* USE_INTERNAL_SETJMP */
static inline
void arch_execute(void *sp, void *func, void *arg)
{
asm volatile ("mov r0, %2;" /* set arg */
"mov sp, %0;" /* set stack */
"mov pc, %1;" /* call func */
""
: : "r"(sp), "r"(func), "r"(arg) : "r0");
}
#endif /* _ARCH_EXECUTE_H_ */

View File

@ -0,0 +1,31 @@
/*
* \brief ARMv6-specific part of the Linux API emulation
* \author Christian Prochaska
* \date 2014-05-28
*/
/*
* Copyright (C) 2014-2016 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.
*/
/*******************
** asm/barrier.h **
*******************/
#define mb() asm volatile ("": : :"memory")
#define rmb() mb()
#define wmb() asm volatile ("": : :"memory")
/*
* This is the "safe" implementation as needed for a configuration
* with SMP enabled.
*/
#define smp_mb() asm volatile ("": : :"memory")
#define smp_rmb() smp_mb()
#define smp_wmb() asm volatile ("": : :"memory")
static inline void barrier() { asm volatile ("": : :"memory"); }

View File

@ -0,0 +1,31 @@
/*
* \brief ARMv7-specific part of the Linux API emulation
* \author Christian Prochaska
* \date 2014-05-28
*/
/*
* Copyright (C) 2014-2016 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.
*/
/*******************
** asm/barrier.h **
*******************/
#define mb() asm volatile ("dsb": : :"memory")
#define rmb() mb()
#define wmb() asm volatile ("dsb st": : :"memory")
/*
* This is the "safe" implementation as needed for a configuration
* with bufferable DMA memory and SMP enabled.
*/
#define smp_mb() asm volatile ("dmb ish": : :"memory")
#define smp_rmb() smp_mb()
#define smp_wmb() asm volatile ("dmb ishst": : :"memory")
static inline void barrier() { asm volatile ("": : :"memory"); }

View File

@ -14,6 +14,23 @@
#ifndef _ARCH_EXECUTE_H_
#define _ARCH_EXECUTE_H_
#if defined(USE_INTERNAL_SETJMP)
#ifdef __cplusplus
extern "C" {
#endif
#define _JBLEN 11
typedef struct _jmp_buf { long _jb[_JBLEN + 1]; } jmp_buf[1];
void _longjmp(jmp_buf, int);
int _setjmp(jmp_buf);
#ifdef __cplusplus
}
#endif
#endif /* USE_INTERNAL_SETJMP */
static inline
void arch_execute(void *sp, void *func, void *arg)
{

View File

@ -15,6 +15,23 @@
#ifndef _ARCH_EXECUTE_H_
#define _ARCH_EXECUTE_H_
#if defined(USE_INTERNAL_SETJMP)
#ifdef __cplusplus
extern "C" {
#endif
#define _JBLEN 12
typedef struct _jmp_buf { long _jb[_JBLEN]; } jmp_buf[1];
void _longjmp(jmp_buf, int);
int _setjmp(jmp_buf);
#ifdef __cplusplus
}
#endif
#endif /* USE_INTERNAL_SETJMP */
static inline
void arch_execute(void *sp, void *func, void *arg)
{

View File

@ -1,17 +0,0 @@
#include <lx/extern_c_begin.h>
#include <lx/lx.h>
#include <lx/extern_c_end.h>
#include <base/printf.h>
void lx_printf(char const *fmt, ...)
{
va_list va;
va_start(va, fmt);
Genode::vprintf(fmt, va);
va_end(va);
}
void lx_vprintf(char const *fmt, va_list va) {
Genode::vprintf(fmt, va); }

View File

@ -13,7 +13,6 @@
#include <base/allocator_avl.h>
#include <base/snprintf.h>
#include <dataspace/client.h>
#include <rm_session/connection.h>
#include <region_map/client.h>
#include <timer_session/connection.h>
#include <trace/timestamp.h>

View File

@ -15,7 +15,6 @@
/* Genode includes */
#include <base/allocator_avl.h>
#include <dataspace/client.h>
#include <rm_session/connection.h>
#include <region_map/client.h>
#include <timer_session/connection.h>
#include <util/string.h>

View File

@ -19,7 +19,6 @@
#include <base/sleep.h>
#include <dataspace/client.h>
#include <timer_session/connection.h>
#include <rm_session/connection.h>
#include <region_map/client.h>
#include <rom_session/connection.h>
#include <util/string.h>

View File

@ -7,27 +7,29 @@
*/
/*
* Copyright (C) 2014-2015 Genode Labs GmbH
* Copyright (C) 2014-2016 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 _LX_EMUL__IMPL__INTERNAL__IRQ_H_
#define _LX_EMUL__IMPL__INTERNAL__IRQ_H_
/* Genode includes */
#include <base/snprintf.h>
#include <base/tslab.h>
#include <irq_session/client.h>
#include <platform_device/client.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/task.h>
/* Linux emulation environment */
#include <lx_emul.h>
namespace Lx { class Irq; }
/* Linux kit includes */
#include <lx_kit/irq.h>
#include <lx_kit/scheduler.h>
class Lx::Irq
namespace Lx_kit { class Irq; }
class Lx_kit::Irq : public Lx::Irq
{
private:
@ -50,7 +52,7 @@ class Lx::Irq
/**
* This contains the Linux-driver handlers
*/
class Handler : public Lx::List<Handler>::Element
class Handler : public Lx_kit::List<Handler>::Element
{
private:
@ -83,15 +85,15 @@ class Lx::Irq
/**
* Context encapsulates the handling of an IRQ
*/
class Context : public Lx::List<Context>::Element
class Context : public Lx_kit::List<Context>::Element
{
private:
Name_composer _name;
Platform::Device &_dev;
Genode::Irq_session_client _irq_sess;
Lx::List<Handler> _handler; /* List of registered handlers */
Lx::Task _task;
Name_composer _name;
Platform::Device &_dev;
Genode::Irq_session_client _irq_sess;
Lx_kit::List<Handler> _handler;
Lx::Task _task;
Genode::Signal_rpc_member<Context> _dispatcher;
@ -141,11 +143,9 @@ class Lx::Irq
*/
void handle_irq()
{
bool handled = false;
/* report IRQ to all clients */
for (Handler *h = _handler.first(); h; h = h->next()) {
if ((handled = h->handle())) break;
h->handle();
}
_irq_sess.ack_irq();
@ -165,10 +165,10 @@ class Lx::Irq
using Context_slab = Genode::Tslab<Context, 3 * sizeof(Context)>;
using Handler_slab = Genode::Tslab<Handler, 3 * sizeof(Handler)>;
Server::Entrypoint &_ep;
Lx::List<Context> _list;
Context_slab _context_alloc;
Handler_slab _handler_alloc;
Server::Entrypoint &_ep;
Lx_kit::List<Context> _list;
Context_slab _context_alloc;
Handler_slab _handler_alloc;
/**
* Find context for given device
@ -180,20 +180,25 @@ class Lx::Irq
return nullptr;
}
Irq(Server::Entrypoint &ep)
Irq(Server::Entrypoint &ep, Genode::Allocator &alloc)
: _ep(ep),
_context_alloc(Genode::env()->heap()),
_handler_alloc(Genode::env()->heap()) { }
_context_alloc(&alloc),
_handler_alloc(&alloc) { }
public:
static Irq &irq(Server::Entrypoint *ep = nullptr);
static Irq &irq(Server::Entrypoint &ep, Genode::Allocator &alloc)
{
static Irq inst(ep, alloc);
return inst;
}
/***********************
** Lx::Irq interface **
***********************/
/**
* Request an IRQ
*/
void request_irq(Platform::Device &dev, irq_handler_t handler,
void *dev_id, irq_handler_t thread_fn = 0)
void *dev_id, irq_handler_t thread_fn = 0) override
{
Context *ctx = _find_context(dev);
@ -210,4 +215,10 @@ class Lx::Irq
}
};
#endif /* _LX_EMUL__IMPL__INTERNAL__IRQ_H_ */
/****************************
** Lx::Irq implementation **
****************************/
Lx::Irq &Lx::Irq::irq(Server::Entrypoint *ep, Genode::Allocator *alloc) {
return Lx_kit::Irq::irq(*ep, *alloc); }

View File

@ -0,0 +1,383 @@
/*
* \brief Linux kit memory allocator
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014-2016 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.
*/
/* Genode includes */
#include <base/allocator_avl.h>
#include <base/env.h>
#include <base/slab.h>
#include <dataspace/client.h>
#include <rm_session/connection.h>
#include <region_map/client.h>
/* Linux kit includes */
#include <lx_kit/types.h>
#include <lx_kit/backend_alloc.h>
#include <lx_kit/malloc.h>
namespace Lx_kit {
class Slab_backend_alloc;
class Slab_alloc;
class Malloc;
}
class Lx_kit::Slab_backend_alloc : public Lx::Slab_backend_alloc,
public Genode::Rm_connection,
public Genode::Region_map_client
{
private:
enum {
VM_SIZE = 64 * 1024 * 1024, /* size of VM region to reserve */
P_BLOCK_SIZE = 2 * 1024 * 1024, /* 2 MB physical contiguous */
V_BLOCK_SIZE = P_BLOCK_SIZE * 2, /* 2 MB virtual used, 2 MB virtual left free to avoid that Allocator_avl merges virtual contiguous regions which are physically non-contiguous */
ELEMENTS = VM_SIZE / V_BLOCK_SIZE, /* MAX number of dataspaces in VM */
};
addr_t _base; /* virt. base address */
Genode::Cache_attribute _cached; /* non-/cached RAM */
Genode::Ram_dataspace_capability _ds_cap[ELEMENTS]; /* dataspaces to put in VM */
addr_t _ds_phys[ELEMENTS]; /* physical bases of dataspaces */
int _index; /* current index in ds_cap */
Genode::Allocator_avl _range; /* manage allocations */
bool _alloc_block()
{
if (_index == ELEMENTS) {
PERR("Slab-backend exhausted!");
return false;
}
try {
_ds_cap[_index] = Lx::backend_alloc(P_BLOCK_SIZE, _cached);
/* attach at index * V_BLOCK_SIZE */
Region_map_client::attach_at(_ds_cap[_index], _index * V_BLOCK_SIZE, P_BLOCK_SIZE, 0);
/* lookup phys. address */
_ds_phys[_index] = Genode::Dataspace_client(_ds_cap[_index]).phys_addr();
} catch (...) { return false; }
/* return base + offset in VM area */
addr_t block_base = _base + (_index * V_BLOCK_SIZE);
++_index;
_range.add_range(block_base, P_BLOCK_SIZE);
return true;
}
public:
Slab_backend_alloc(Genode::Cache_attribute cached)
:
Region_map_client(Rm_connection::create(VM_SIZE)),
_cached(cached), _index(0), _range(Genode::env()->heap())
{
/* reserver attach us, anywere */
_base = Genode::env()->rm_session()->attach(dataspace());
}
static Slab_backend_alloc &mem()
{
static Lx_kit::Slab_backend_alloc inst(Genode::CACHED);
return inst;
}
static Slab_backend_alloc &dma()
{
static Lx_kit::Slab_backend_alloc inst(Genode::UNCACHED);
return inst;
}
/**************************************
** Lx::Slab_backend_alloc interface **
**************************************/
bool alloc(size_t size, void **out_addr) override
{
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) {
_range.free(addr); }
void free(void *addr, size_t size) override { _range.free(addr, size); }
size_t overhead(size_t size) const override { return 0; }
bool need_size_for_free() const override { return false; }
addr_t phys_addr(addr_t addr)
{
if (addr < _base || addr >= (_base + VM_SIZE))
return ~0UL;
int index = (addr - _base) / V_BLOCK_SIZE;
/* physical base of dataspace */
addr_t phys = _ds_phys[index];
if (!phys)
return ~0UL;
/* add offset */
phys += (addr - _base - (index * V_BLOCK_SIZE));
return phys;
}
addr_t virt_addr(addr_t phys)
{
for (unsigned i = 0; i < ELEMENTS; i++) {
if (_ds_cap[i].valid() &&
phys >= _ds_phys[i] && phys < _ds_phys[i] + P_BLOCK_SIZE)
return _base + i * V_BLOCK_SIZE + phys - _ds_phys[i];
}
PWRN("virt_addr(0x%lx) - no translation", phys);
return 0;
}
addr_t start() const { return _base; }
addr_t end() const { return _base + VM_SIZE - 1; }
};
class Lx_kit::Malloc : public Lx::Malloc
{
private:
enum {
SLAB_START_LOG2 = 3, /* 8 B */
SLAB_STOP_LOG2 = MAX_SIZE_LOG2,
NUM_SLABS = (SLAB_STOP_LOG2 - SLAB_START_LOG2) + 1,
};
typedef Genode::addr_t addr_t;
typedef Lx::Slab_alloc Slab_alloc;
typedef Lx::Slab_backend_alloc Slab_backend_alloc;
Slab_backend_alloc &_back_allocator;
Slab_alloc *_allocator[NUM_SLABS];
Genode::Cache_attribute _cached; /* cached or un-cached memory */
addr_t _start; /* VM region of this allocator */
addr_t _end;
/**
* Set 'value' at 'addr'
*/
void _set_at(addr_t addr, addr_t value) { *((addr_t *)addr) = value; }
/**
* Retrieve slab index belonging to given address
*/
unsigned _slab_index(Genode::addr_t **addr)
{
using namespace Genode;
/* get index */
addr_t index = *(*addr - 1);
/*
* If index large, we use aligned memory, retrieve beginning of slab entry
* and read index from there
*/
if (index > 32) {
*addr = (addr_t *)*(*addr - 1);
index = *(*addr - 1);
}
return index;
}
/**
* Get the originally requested size of the allocation
*/
size_t _get_orig_size(Genode::addr_t **addr)
{
using namespace Genode;
addr_t index = *(*addr - 1);
if (index > 32) {
*addr = (addr_t *) * (*addr - 1);
}
return *(*addr - 2);
}
public:
Malloc(Slab_backend_alloc &alloc, Genode::Cache_attribute cached)
:
_back_allocator(alloc), _cached(cached), _start(alloc.start()),
_end(alloc.end())
{
/* init slab allocators */
for (unsigned i = SLAB_START_LOG2; i <= SLAB_STOP_LOG2; i++)
_allocator[i - SLAB_START_LOG2] = new (Genode::env()->heap())
Slab_alloc(1U << i, alloc);
}
static Malloc & mem()
{
static Malloc inst(Slab_backend_alloc::mem(), Genode::CACHED);
return inst;
}
static Malloc & dma()
{
static Malloc inst(Slab_backend_alloc::dma(), Genode::UNCACHED);
return inst;
}
/**************************
** Lx::Malloc interface **
**************************/
void *alloc(Genode::size_t size, int align = 0, Genode::addr_t *phys = 0)
{
using namespace Genode;
/* save requested size */
size_t orig_size = size;
size += sizeof(addr_t);
/* += slab index + aligment size */
size += sizeof(addr_t) + (align > 2 ? (1 << align) : 0);
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) {
PERR("Slab too large %u reqested %zu cached %d", 1U << msb, size, _cached);
return 0;
}
addr_t addr = _allocator[msb - SLAB_START_LOG2]->alloc();
if (!addr) {
PERR("Failed to get slab for %u", 1 << msb);
return 0;
}
_set_at(addr, orig_size);
addr += sizeof(addr_t);
_set_at(addr, msb - SLAB_START_LOG2);
addr += sizeof(addr_t);
if (align > 2) {
/* save */
addr_t ptr = addr;
addr_t align_val = (1U << align);
addr_t align_mask = align_val - 1;
/* align */
addr = (addr + align_val) & ~align_mask;
/* write start address before aligned address */
_set_at(addr - sizeof(addr_t), ptr);
}
if (phys)
*phys = _back_allocator.phys_addr(addr);
return (addr_t *)addr;
}
void free(void const *a)
{
using namespace Genode;
addr_t *addr = (addr_t *)a;
/* XXX changes addr */
unsigned nr = _slab_index(&addr);
/* we need to decrease addr by 2, orig_size and index come first */
_allocator[nr]->free((void *)(addr - 2));
}
void *alloc_large(size_t size)
{
void *addr;
if (!_back_allocator.alloc(size, &addr)) {
PERR("Large back end allocation failed (%zu bytes)", size);
return nullptr;
}
return addr;
}
void free_large(void *ptr)
{
_back_allocator.free(ptr);
}
size_t size(void const *a)
{
using namespace Genode;
addr_t *addr = (addr_t *)a;
/* XXX changes addr */
return _get_orig_size(&addr);
}
Genode::addr_t phys_addr(void *a) {
return _back_allocator.phys_addr((addr_t)a); }
Genode::addr_t virt_addr(Genode::addr_t phys) {
return _back_allocator.virt_addr(phys); }
bool inside(addr_t const addr) const { return (addr > _start) && (addr <= _end); }
};
/*******************************
** Lx::Malloc implementation **
*******************************/
/**
* Cached memory backend allocator
*/
Lx::Slab_backend_alloc &Lx::Slab_backend_alloc::mem() {
return Lx_kit::Slab_backend_alloc::mem(); }
/**
* DMA memory backend allocator
*/
Lx::Slab_backend_alloc &Lx::Slab_backend_alloc::dma() {
return Lx_kit::Slab_backend_alloc::dma(); }
/**
* Cached memory allocator
*/
Lx::Malloc &Lx::Malloc::mem() {
return Lx_kit::Malloc::mem(); }
/**
* DMA memory allocator
*/
Lx::Malloc &Lx::Malloc::dma() {
return Lx_kit::Malloc::dma(); }

View File

@ -5,44 +5,42 @@
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 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 _LX_EMUL__IMPL__INTERNAL__MAPPED_IO_MEM_RANGE_H_
#define _LX_EMUL__IMPL__INTERNAL__MAPPED_IO_MEM_RANGE_H_
/* Genode includes */
#include <os/attached_dataspace.h>
#include <io_mem_session/io_mem_session.h>
#include <rm_session/connection.h>
#include <region_map/client.h>
/* Linux emulation environment */
#include <lx_emul.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/list.h>
#include <lx_kit/internal/list.h>
#include <lx_kit/mapped_io_mem_range.h>
#include <lx_kit/pci_dev_registry.h>
#include <lx_kit/types.h>
namespace Lx {
namespace Lx_kit { class Mapped_io_mem_range; }
class Mapped_io_mem_range;
void *ioremap(resource_size_t, unsigned long, Genode::Cache_attribute);
void iounmap(volatile void*);
Genode::Dataspace_capability ioremap_lookup(Genode::addr_t, Genode::size_t);
}
/**
* Representation of a locally-mapped MMIO range
*
* This class is supposed to be a private utility to support 'ioremap'.
*/
class Lx::Mapped_io_mem_range : public Lx::List<Mapped_io_mem_range>::Element
class Lx_kit::Mapped_io_mem_range : public Lx_kit::List<Mapped_io_mem_range>::Element,
public Genode::Rm_connection
{
private:
Genode::size_t const _size;
Genode::addr_t const _phys;
Genode::Rm_connection _rm;
Genode::Region_map_client _region_map;
Genode::Attached_dataspace _ds;
Genode::addr_t const _virt;
@ -54,7 +52,7 @@ class Lx::Mapped_io_mem_range : public Lx::List<Mapped_io_mem_range>::Element
Genode::addr_t offset)
: _size(size),
_phys(phys),
_region_map(_rm.create(size)),
_region_map(Rm_connection::create(size)),
_ds(_region_map.dataspace()),
_virt((Genode::addr_t)_ds.local_addr<void>() | (phys &0xfffUL)) {
_region_map.attach_at(ds_cap, 0, size, offset); }
@ -81,16 +79,20 @@ class Lx::Mapped_io_mem_range : public Lx::List<Mapped_io_mem_range>::Element
};
static Lx::List<Lx::Mapped_io_mem_range> ranges;
static Lx_kit::List<Lx_kit::Mapped_io_mem_range> ranges;
void *Lx::ioremap(resource_size_t phys_addr, unsigned long size,
/********************************************
** Lx_kit::Mapped_io_mem_range implementation **
********************************************/
void *Lx::ioremap(addr_t phys_addr, unsigned long size,
Genode::Cache_attribute cache_attribute)
{
using namespace Genode;
/* search for the requested region within the already mapped ranges */
for (Lx::Mapped_io_mem_range *r = ranges.first(); r; r = r->next()) {
for (Lx_kit::Mapped_io_mem_range *r = ranges.first(); r; r = r->next()) {
if (r->phys_range(phys_addr, size)) {
void * const virt = (void *)(r->virt() + phys_addr - r->phys());
@ -100,19 +102,19 @@ void *Lx::ioremap(resource_size_t phys_addr, unsigned long size,
}
}
addr_t offset;
addr_t offset = 0;
Io_mem_dataspace_capability ds_cap =
Lx::pci_dev_registry()->io_mem(phys_addr, cache_attribute,
size, offset);
if (!ds_cap.valid()) {
PERR("Failed to request I/O memory: [%zx,%lx)", phys_addr,
PERR("Failed to request I/O memory: [%lx,%lx)", phys_addr,
phys_addr + size);
return nullptr;
}
Lx::Mapped_io_mem_range *io_mem =
new (env()->heap()) Lx::Mapped_io_mem_range(phys_addr, size,
Lx_kit::Mapped_io_mem_range *io_mem =
new (env()->heap()) Lx_kit::Mapped_io_mem_range(phys_addr, size,
ds_cap, offset);
ranges.insert(io_mem);
@ -120,8 +122,7 @@ void *Lx::ioremap(resource_size_t phys_addr, unsigned long size,
PLOG("ioremap: mapped phys 0x%lx (size %lx) to virt 0x%lx",
(long)phys_addr, (long)size, (long)io_mem->virt());
addr_t const sub_page_offset = phys_addr & 0xfff;
return (void *)(io_mem->virt() + sub_page_offset);
return (void *)io_mem->virt();
}
void Lx::iounmap(volatile void * virt)
@ -129,7 +130,7 @@ void Lx::iounmap(volatile void * virt)
using namespace Genode;
/* search for the requested region within the already mapped ranges */
for (Lx::Mapped_io_mem_range *r = ranges.first(); r; r = r->next()) {
for (Lx_kit::Mapped_io_mem_range *r = ranges.first(); r; r = r->next()) {
if (r->virt() == (addr_t)virt) {
ranges.remove(r);
@ -143,11 +144,9 @@ Genode::Dataspace_capability
Lx::ioremap_lookup(Genode::addr_t virt_addr, Genode::size_t size)
{
/* search for the requested region within the already mapped ranges */
for (Lx::Mapped_io_mem_range *r = ranges.first(); r; r = r->next())
for (Lx_kit::Mapped_io_mem_range *r = ranges.first(); r; r = r->next())
if (r->virt_range(virt_addr, size))
return r->cap();
return Genode::Dataspace_capability();
}
#endif /* _LX_EMUL__IMPL__INTERNAL__MAPPED_IO_MEM_RANGE_H_ */

View File

@ -7,33 +7,35 @@
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
* Copyright (C) 2014-2016 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 _LX_EMUL__IMPL__INTERNAL__PCI_BACKEND_ALLOC_H_
#define _LX_EMUL__IMPL__INTERNAL__PCI_BACKEND_ALLOC_H_
/* Genode includes */
#include <base/object_pool.h>
#include <base/env.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/slab_backend_alloc.h>
/* XXX only because of struct pci_dev */
#include <lx_emul.h>
namespace Lx {
/* Linux emulation environment includes */
#include <lx_kit/backend_alloc.h>
#include <lx_kit/pci_dev_registry.h>
namespace Lx_kit {
struct Memory_object_base;
struct Ram_object;
struct Dma_object;
extern Genode::Object_pool<Memory_object_base> memory_pool;
Genode::Object_pool<Memory_object_base> memory_pool;
};
struct Lx::Memory_object_base : Genode::Object_pool<Memory_object_base>::Entry
struct Lx_kit::Memory_object_base : Genode::Object_pool<Memory_object_base>::Entry
{
Memory_object_base(Genode::Ram_dataspace_capability cap)
: Genode::Object_pool<Memory_object_base>::Entry(cap) {}
@ -49,7 +51,7 @@ struct Lx::Memory_object_base : Genode::Object_pool<Memory_object_base>::Entry
};
struct Lx::Ram_object : Memory_object_base
struct Lx_kit::Ram_object : Memory_object_base
{
Ram_object(Genode::Ram_dataspace_capability cap)
: Memory_object_base(cap) {}
@ -58,7 +60,7 @@ struct Lx::Ram_object : Memory_object_base
};
struct Lx::Dma_object : Memory_object_base
struct Lx_kit::Dma_object : Memory_object_base
{
Dma_object(Genode::Ram_dataspace_capability cap)
: Memory_object_base(cap) {}
@ -67,10 +69,15 @@ struct Lx::Dma_object : Memory_object_base
};
/*********************************
** Lx::Backend_alloc interface **
*********************************/
Genode::Ram_dataspace_capability
Lx::backend_alloc(Genode::addr_t size, Genode::Cache_attribute cached)
{
using namespace Genode;
using namespace Lx_kit;
Memory_object_base *o;
Genode::Ram_dataspace_capability cap;
@ -100,6 +107,7 @@ Lx::backend_alloc(Genode::addr_t size, Genode::Cache_attribute cached)
void Lx::backend_free(Genode::Ram_dataspace_capability cap)
{
using namespace Genode;
using namespace Lx_kit;
Memory_object_base *object;
memory_pool.apply(cap, [&] (Memory_object_base *o) {
@ -114,5 +122,19 @@ void Lx::backend_free(Genode::Ram_dataspace_capability cap)
}
#endif /* _LX_EMUL__IMPL__INTERNAL__PCI_BACKEND_ALLOC_H_ */
/********************
** Pci singletons **
********************/
Platform::Connection *Lx::pci()
{
static Platform::Connection _pci;
return &_pci;
}
Lx::Pci_dev_registry *Lx::pci_dev_registry()
{
static Lx::Pci_dev_registry _pci_dev_registry;
return &_pci_dev_registry;
}

View File

@ -0,0 +1,445 @@
/*
* \brief Linux kit memory allocator
* \author Sebastian Sumpf
* \date 2016-04-20
*/
/*
* Copyright (C) 2016 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.
*/
/* Genode includes */
#include <base/console.h>
#include <base/printf.h>
/* local includes */
#include <lx_emul.h>
namespace Lx { class Console; }
extern "C" int stdout_write(const char *s);
static const bool verbose_console = false;
/**
* Format string command representation
*/
class Format_command
{
public:
enum Type { INT, UINT, STRING, CHAR, PTR, PERCENT, VA_FORMAT, MAC,
IPV4, INVALID };
enum Length { DEFAULT, LONG, SIZE_T, LONG_LONG };
private:
/**
* Read decimal value from string
*/
int decode_decimal(const char *str, int *consumed)
{
int res = 0;
while (1) {
char c = str[*consumed];
if (!c || c < '0' || c > '0' + 9)
return res;
res = (res * 10) + c - '0';
(*consumed)++;
}
}
public:
Type type = INVALID; /* format argument type */
Length length = DEFAULT; /* format argument length */
int padding = 0; /* min number of characters to print */
int base = 10; /* base of numeric arguments */
bool zeropad = false; /* pad with zero instead of space */
bool uppercase = false; /* use upper case for hex numbers */
bool prefix = false; /* prefix with 0x */
int consumed = 0; /* nb of consumed format string chars */
/**
* Constructor
*
* \param format begin of command in format string
*/
explicit Format_command(const char *format)
{
/* check for command begin and eat the character */
if (format[consumed] != '%') return;
if (!format[++consumed]) return;
/* check for %$x syntax */
prefix = (format[consumed] == '#');
if (prefix && !format[++consumed]) return;
/* heading zero indicates zero-padding */
zeropad = (format[consumed] == '0');
/* read decimal padding value */
padding = decode_decimal(format, &consumed);
if (!format[consumed]) return;
/* decode length */
switch (format[consumed]) {
case 'l':
{
/* long long ints are marked by a subsequenting 'l' character */
bool is_long_long = (format[consumed + 1] == 'l');
length = is_long_long ? LONG_LONG : LONG;
consumed += is_long_long ? 2 : 1;
break;
}
case 'z':
case 'Z':
length = SIZE_T;
consumed++;
break;
case 'p':
length = LONG;
break;
default: break;
}
if (!format[consumed]) return;
/* decode type */
switch (format[consumed]) {
case 'd':
case 'i': type = INT; base = 10; break;
case 'o': type = UINT; base = 8; break;
case 'u': type = UINT; base = 10; break;
case 'x': type = UINT; base = 16; break;
case 'X': type = UINT; base = 16; uppercase = 1; break;
case 'p': type = PTR; base = 16; break;
case 'c': type = CHAR; break;
case 's': type = STRING; break;
case '%': type = PERCENT; break;
case 0: return;
default: break;
}
/* eat type character */
consumed++;
if (type != PTR || !format[consumed])
return;
switch (format[consumed]) {
case 'V': type = VA_FORMAT; break;
case 'M': type = MAC; base = 16; padding = 2; break;
case 'I':
if (format[consumed + 1] != '4') break;
consumed++;
type = IPV4; base = 10;
break;
default: return;
}
consumed++;
}
int numeric()
{
return (type == INT || type == UINT || type == PTR);
}
};
/**
* Convert digit to ASCII value
*/
static char ascii(int digit, int uppercase = 0)
{
if (digit > 9)
return digit + (uppercase ? 'A' : 'a') - 10;
return digit + '0';
}
class Lx::Console
{
private:
enum { BUF_SIZE = 216 };
char _buf[BUF_SIZE + 1];
unsigned _idx = 0;
void _flush()
{
if (!_idx)
return;
_buf[_idx] = 0;
stdout_write(_buf);
_idx = 0;
}
/**
* Output signed value with the specified base
*/
template <typename T>
void _out_signed(T value, unsigned base)
{
/**
* for base 8, the number of digits is the number of value bytes times 3
* at a max, because 0xff is 0o377 and accumulating this implies a
* strictly decreasing factor
*/
char buf[sizeof(value)*3];
/* set flag if value is negative */
int neg = value < 0 ? 1 : 0;
/* get absolute value */
value = value < 0 ? -value : value;
int i = 0;
/* handle zero as special case */
if (value == 0)
buf[i++] = ascii(0);
/* fill buffer starting with the least significant digits */
else
for (; value > 0; value /= base)
buf[i++] = ascii(value % base);
/* add sign to buffer for negative values */
if (neg)
_out_char('-');
/* output buffer in reverse order */
for (; i--; )
_out_char(buf[i]);
}
/**
* Output unsigned value with the specified base and padding
*/
template <typename T>
void _out_unsigned(T value, unsigned base, int pad)
{
/**
* for base 8, the number of digits is the number of value bytes times 3
* at a max, because 0xff is 0o377 and accumulating this implies a
* strictly decreasing factor
*/
char buf[sizeof(value)*3];
int i = 0;
/* handle zero as special case */
if (value == 0) {
buf[i++] = ascii(0);
pad--;
}
/* fill buffer starting with the least significant digits */
for (; value > 0; value /= base, pad--)
buf[i++] = ascii(value % base);
/* add padding zeros */
for (; pad-- > 0; )
_out_char(ascii(0));
/* output buffer in reverse order */
for (; i--; )
_out_char(buf[i]);
}
protected:
void _out_char(char c)
{
if (c == '\n' || _idx == BUF_SIZE || c == 0)
_flush();
else
_buf[_idx++] = c;
}
void _out_string(const char *str)
{
if (str)
while (*str) _out_char(*str++);
else
_flush();
}
public:
static Console &c()
{
static Console _inst;
return _inst;
}
void vprintf(const char *format, va_list list)
{
while (*format) {
/* eat and output plain characters */
if (*format != '%') {
_out_char(*format++);
continue;
}
/* parse format argument descriptor */
Format_command cmd(format);
/* read numeric argument from va_list */
long long numeric_arg = 0;
if (cmd.numeric()) {
switch (cmd.length) {
case Format_command::LONG_LONG:
numeric_arg = va_arg(list, long long);
break;
case Format_command::LONG:
numeric_arg = (cmd.type == Format_command::UINT) ?
(long long)va_arg(list, unsigned long) : va_arg(list, long);
break;
case Format_command::SIZE_T:
numeric_arg = va_arg(list, size_t);
break;
case Format_command::DEFAULT:
numeric_arg = (cmd.type == Format_command::UINT) ?
(long long)va_arg(list, unsigned int) : va_arg(list, int);
break;
}
}
/* call type-specific output routines */
switch (cmd.type) {
case Format_command::INT:
if (cmd.length == Format_command::LONG_LONG)
_out_signed<long long>(numeric_arg, cmd.base);
else
_out_signed<long>(numeric_arg, cmd.base);
break;
case Format_command::UINT:
if (cmd.prefix && cmd.base == 16)
_out_string("0x");
if (cmd.length == Format_command::LONG_LONG) {
_out_unsigned<unsigned long long>(numeric_arg, cmd.base, cmd.padding);
break;
}
/* fall through */
case Format_command::PTR:
_out_unsigned<unsigned long>(numeric_arg, cmd.base, cmd.padding);
break;
case Format_command::CHAR:
_out_char(va_arg(list, int));
break;
case Format_command::STRING:
_out_string(va_arg(list, const char *));
break;
case Format_command::PERCENT:
_out_char('%');
break;
case Format_command::VA_FORMAT: /* %pV */
{
va_list va;
va_format *vf = va_arg(list, va_format *);
va_copy(va, *vf->va);
vprintf(vf->fmt, va);
va_end(va);
}
break;
case Format_command::MAC: /* %pM */
{
unsigned char const *mac = va_arg(list, unsigned char const *);
for (int i = 0; i < 6; i++) {
if (i) _out_char(':');
_out_unsigned<unsigned char>(mac[i], cmd.base, cmd.padding);
}
break;
}
case Format_command::IPV4: /* %pI4 */
{
unsigned char const *ip = va_arg(list, unsigned char const *);
for (int i = 0; i < 4; i++) {
if (i) _out_char('.');
_out_unsigned<unsigned char>(ip[i], cmd.base, cmd.padding);
}
}
break;
case Format_command::INVALID:
_out_string("<warning: unsupported format string argument>");
/* consume the argument of the unsupported command */
va_arg(list, long);
break;
}
/* proceed with format string after command */
format += cmd.consumed;
}
}
};
void lx_printf(char const *fmt, ...)
{
if (verbose_console)
PDBG("[%p] %s", __builtin_return_address(0), fmt);
va_list va;
va_start(va, fmt);
Lx::Console::c().vprintf(fmt, va);
va_end(va);
}
void lx_vprintf(char const *fmt, va_list va) {
Lx::Console::c().vprintf(fmt, va); }

View File

@ -7,59 +7,44 @@
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
* Copyright (C) 2014-2016 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 _LX_EMUL__IMPL__INTERNAL__SCHEDULER_H_
#define _LX_EMUL__IMPL__INTERNAL__SCHEDULER_H_
/* Genode includes */
#include <base/env.h>
#include <base/lock.h>
#include <base/printf.h>
#include <base/sleep.h>
#include <base/thread.h>
#include <timer_session/connection.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/task.h>
#include <lx_emul/impl/internal/debug.h>
#include <lx_kit/internal/debug.h>
#include <lx_kit/scheduler.h>
namespace Lx {
#include <lx_kit/timer.h>
namespace Lx_kit {
class Scheduler;
/**
* Return singleton instance of the scheduler
*
* Implementation must be provided by the driver.
*/
Scheduler &scheduler();
/**
* Called each time when a scheduling decision is taken
*
* Must be provided by the compilation unit that includes 'scheduler.h',
* e.g., by also including 'timer.h'.
*/
static inline void timer_update_jiffies();
}
class Lx::Scheduler
class Lx_kit::Scheduler : public Lx::Scheduler
{
private:
bool verbose = false;
Lx::List<Lx::Task> _present_list;
Genode::Lock _present_list_mutex;
Lx_kit::List<Lx::Task> _present_list;
Genode::Lock _present_list_mutex;
Task *_current = nullptr; /* currently scheduled task */
Lx::Task *_current = nullptr; /* currently scheduled task */
bool _run_task(Task *);
bool _run_task(Lx::Task *);
/*
* Support for logging
@ -116,10 +101,11 @@ class Lx::Scheduler
new (Genode::env()->heap()) Logger(*this, 10);
}
/**
* Return currently scheduled task
*/
Task *current()
/*****************************
** Lx::Scheduler interface **
*****************************/
Lx::Task *current() override
{
if (!_current) {
PERR("BUG: _current is zero!");
@ -129,10 +115,10 @@ class Lx::Scheduler
return _current;
}
/**
* Add new task to the present list
*/
void add(Task *task)
bool active() const override {
return _current != nullptr; }
void add(Lx::Task *task) override
{
Lx::Task *p = _present_list.first();
for ( ; p; p = p->next()) {
@ -145,12 +131,12 @@ class Lx::Scheduler
_present_list.append(task);
}
/**
* Schedule all present tasks
*
* Returns if no task is runnable.
*/
void schedule()
void remove(Lx::Task *task) override
{
_present_list.remove(task);
}
void schedule() override
{
bool at_least_one = false;
@ -168,7 +154,7 @@ class Lx::Scheduler
Lx::timer_update_jiffies();
bool was_run = false;
for (Task *t = _present_list.first(); t; t = t->next()) {
for (Lx::Task *t = _present_list.first(); t; t = t->next()) {
/* update current before running task */
_current = t;
@ -190,12 +176,7 @@ class Lx::Scheduler
_current = nullptr;
}
/**
* Log current state of tasks in present list (debug)
*
* Log lines are prefixed with 'prefix'.
*/
void log_state(char const *prefix)
void log_state(char const *prefix) override
{
unsigned i;
Lx::Task *t;
@ -208,6 +189,10 @@ class Lx::Scheduler
};
/*****************************
** Lx::Task implementation **
*****************************/
Lx::Task::Task(void (*func)(void*), void *arg, char const *name,
Priority priority, Scheduler &scheduler)
:
@ -216,15 +201,26 @@ Lx::Task::Task(void (*func)(void*), void *arg, char const *name,
{
scheduler.add(this);
PDBGV("name: '%s' func: %p arg: %p prio: %u t: %p", name, func, arg, priority, this);
if (verbose)
PDBG("name: '%s' func: %p arg: %p prio: %u t: %p", name, func, arg, priority, this);
}
void Lx::Task::_deinit()
Lx::Task::~Task()
{
_scheduler.remove(this);
if (_stack)
Genode::Thread::myself()->free_secondary_stack(_stack);
}
#endif /* _LX_EMUL__IMPL__INTERNAL__SCHEDULER_H_ */
/**********************************
** Lx::Scheduler implementation **
**********************************/
Lx::Scheduler &Lx::scheduler()
{
static Lx_kit::Scheduler inst;
return inst;
}

View File

@ -0,0 +1,91 @@
/* $NetBSD: _setjmp.S,v 1.5 2003/04/05 23:08:51 bjh21 Exp $ */
/*
* Copyright (c) 1997 Mark Brinicombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Mark Brinicombe
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
//#include <machine/asm.h>
__FBSDID("$FreeBSD$");
/*
* C library -- _setjmp, _longjmp
*
* _longjmp(a,v)
* will generate a "return(v)" from the last call to
* _setjmp(a)
* by restoring registers from the stack.
* The previous signal state is NOT restored.
*
* Note: r0 is the return value
* r1-r3 are scratch registers in functions
*/
ENTRY(_setjmp)
ldr r1, .L_setjmp_magic
str r1, [r0], #4
/* SOFTFP */
add r0, r0, #52
/* Store integer registers */
stmia r0, {r4-r14}
mov r0, #0x00000000
RET
.L_setjmp_magic:
.word _JB_MAGIC__SETJMP
WEAK_ALIAS(___longjmp, _longjmp)
ENTRY(_longjmp)
ldr r2, .L_setjmp_magic
ldr r3, [r0], #4
teq r2, r3
bne botch
/* SOFTFP */
add r0, r0, #52
/* Restore integer registers */
ldmia r0, {r4-r14}
/* Validate sp and r14 */
teq sp, #0
teqne r14, #0
beq botch
/* Set return value */
mov r0, r1
teq r0, #0x00000000
moveq r0, #0x00000001
RET
/* validation failed, die die die. */
botch:
b .

View File

@ -0,0 +1,79 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
.asciz "@(#)_setjmp.s 5.1 (Berkeley) 4/23/90"
#endif /* LIBC_SCCS and not lint */
//#include <machine/asm.h>
/*
* C library -- _setjmp, _longjmp
*
* _longjmp(a,v)
* will generate a "return(v)" from the last call to
* _setjmp(a)
* by restoring registers from the environment 'a'.
* The previous signal state is NOT restored.
*/
.text; .p2align 2,0x90
.globl _setjmp; .type _setjmp,@function; _setjmp:
movl 4(%esp),%eax
movl 0(%esp),%edx
movl %edx, 0(%eax) /* rta */
movl %ebx, 4(%eax)
movl %esp, 8(%eax)
movl %ebp,12(%eax)
movl %esi,16(%eax)
movl %edi,20(%eax)
fnstcw 24(%eax)
xorl %eax,%eax
ret
.size _setjmp, . - _setjmp
.text; .p2align 2,0x90
.globl _longjmp; .type _longjmp,@function; _longjmp:
movl 4(%esp),%edx
movl 8(%esp),%eax
movl 0(%edx),%ecx
movl 4(%edx),%ebx
movl 8(%edx),%esp
movl 12(%edx),%ebp
movl 16(%edx),%esi
movl 20(%edx),%edi
fldcw 24(%edx)
testl %eax,%eax
jnz 1f
incl %eax
1: movl %ecx,0(%esp)
ret
.size _longjmp, . - _longjmp

View File

@ -0,0 +1,93 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
.asciz "@(#)_setjmp.s 5.1 (Berkeley) 4/23/90"
#endif /* LIBC_SCCS and not lint */
//#include <machine/asm.h>
/*
* C library -- _setjmp, _longjmp
*
* _longjmp(a,v)
* will generate a "return(v)" from the last call to
* _setjmp(a)
* by restoring registers from the environment 'a'.
* The previous signal state is NOT restored.
*/
.text; .p2align 4,0x90
.globl _setjmp; .type _setjmp,@function; _setjmp:
movq %rdi,%rax
movq 0(%rsp),%rdx /* retval */
movq %rdx, 0(%rax) /* 0; retval */
movq %rbx, 8(%rax) /* 1; rbx */
movq %rsp,16(%rax) /* 2; rsp */
movq %rbp,24(%rax) /* 3; rbp */
movq %r12,32(%rax) /* 4; r12 */
movq %r13,40(%rax) /* 5; r13 */
movq %r14,48(%rax) /* 6; r14 */
movq %r15,56(%rax) /* 7; r15 */
fnstcw 64(%rax) /* 8; fpu cw */
stmxcsr 68(%rax) /* and mxcsr */
xorq %rax,%rax
ret
.size _setjmp, . - _setjmp
.text; .p2align 4,0x90
.globl _longjmp; .type _longjmp,@function; _longjmp:
movq %rdi,%rdx
/* Restore the mxcsr, but leave exception flags intact. */
stmxcsr -4(%rsp)
movl 68(%rdx),%eax
andl $0xffffffc0,%eax
movl -4(%rsp),%edi
andl $0x3f,%edi
xorl %eax,%edi
movl %edi,-4(%rsp)
ldmxcsr -4(%rsp)
movq %rsi,%rax /* retval */
movq 0(%rdx),%rcx
movq 8(%rdx),%rbx
movq 16(%rdx),%rsp
movq 24(%rdx),%rbp
movq 32(%rdx),%r12
movq 40(%rdx),%r13
movq 48(%rdx),%r14
movq 56(%rdx),%r15
fldcw 64(%rdx)
testq %rax,%rax
jnz 1f
incq %rax
1: movq %rcx,0(%rsp)
ret
.size _longjmp, . - _longjmp

View File

@ -7,85 +7,90 @@
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
* Copyright (C) 2014-2016 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 _LX_EMUL__IMPL__INTERNAL__TIMER_H_
#define _LX_EMUL__IMPL__INTERNAL__TIMER_H_
/* Genode includes */
#include <os/server.h>
#include <base/tslab.h>
#include <timer_session/connection.h>
/* Linux kit includes */
#include <lx_kit/internal/list.h>
#include <lx_kit/scheduler.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/task.h>
#include <lx_emul/impl/internal/scheduler.h>
#include <lx_emul.h>
namespace Lx {
class Timer;
/**
* Return singleton instance of timer
*
* \param ep entrypoint used handle timeout signals,
* to be specified at the first call of the function,
* which implicitly initializes the timer
* \param jiffies_ptr pointer to jiffies counter to be periodically
* updated
*/
Timer &timer(Server::Entrypoint *ep = nullptr,
unsigned long *jiffies_ptr = nullptr);
/**
* Blue-print implementation of 'timer' function
*/
static inline Timer &_timer_impl(Server::Entrypoint *ep,
unsigned long *jiffies_ptr);
static inline void timer_update_jiffies();
static inline void run_timer(void *);
}
#include <lx_kit/timer.h>
class Lx::Timer
namespace Lx_kit { class Timer; }
class Lx_kit::Timer : public Lx::Timer
{
public:
/**
* Context encapsulates a regular linux timer_list
*/
struct Context : public Lx::List<Context>::Element
struct Context : public Lx_kit::List<Context>::Element
{
enum { INVALID_TIMEOUT = ~0UL };
struct timer_list *timer;
Type type;
void *timer;
bool pending { false };
unsigned long timeout { INVALID_TIMEOUT }; /* absolute in jiffies */
bool programmed { false };
Context(struct timer_list *timer) : timer(timer) { }
Context(struct timer_list *timer) : type(LIST), timer(timer) { }
Context(struct hrtimer *timer) : type(HR), timer(timer) { }
void expires(unsigned long e)
{
if (type == LIST)
static_cast<timer_list *>(timer)->expires = e;
}
void function()
{
switch (type) {
case LIST:
{
timer_list *t = static_cast<timer_list *>(timer);
if (t->function)
t->function(t->data);
}
break;
case HR:
{
hrtimer *t = static_cast<hrtimer *>(timer);
if (t->function)
t->function(t);
}
break;
}
}
};
private:
unsigned long &_jiffies;
::Timer::Connection _timer_conn;
Lx::List<Context> _list;
Lx_kit::List<Context> _list;
Lx::Task _timer_task;
Genode::Signal_rpc_member<Lx::Timer> _dispatcher;
Genode::Signal_rpc_member<Lx_kit::Timer> _dispatcher;
Genode::Tslab<Context, 32 * sizeof(Context)> _timer_alloc;
/**
* Lookup local timer
*/
Context *_find_context(struct timer_list const *timer)
Context *_find_context(void const *timer)
{
for (Context *c = _list.first(); c; c = c->next())
if (c->timer == timer)
@ -141,7 +146,7 @@ class Lx::Timer
* struct timer_list because the wireless stack checks
* it directly.
*/
ctx->timer->expires = expires;
ctx->expires(expires);
Context *c;
for (c = _list.first(); c; c = c->next())
@ -170,27 +175,55 @@ class Lx::Timer
Timer(Server::Entrypoint &ep, unsigned long &jiffies)
:
_jiffies(jiffies),
_timer_task(run_timer, nullptr, "timer", Lx::Task::PRIORITY_2,
Lx::scheduler()),
_dispatcher(ep, *this, &Lx::Timer::_handle),
_timer_task(Timer::run_timer, reinterpret_cast<void*>(this),
"timer", Lx::Task::PRIORITY_2, Lx::scheduler()),
_dispatcher(ep, *this, &Lx_kit::Timer::_handle),
_timer_alloc(Genode::env()->heap())
{
_timer_conn.sigh(_dispatcher);
}
/**
* Add new linux timer
*/
void add(struct timer_list *timer)
Context* first() { return _list.first(); }
unsigned long jiffies() const { return _jiffies; }
static void run_timer(void *p)
{
Context *t = new (&_timer_alloc) Context(timer);
Timer &t = *reinterpret_cast<Timer*>(p);
while (1) {
Lx::scheduler().current()->block_and_schedule();
Lx_kit::Timer::Context *ctx = t.first();
if (!ctx || ctx->timeout > t.jiffies())
continue;;
ctx->pending = false;
ctx->function();
if (!ctx->pending)
t.del(ctx->timer);
t.schedule_next();
}
}
/*************************
** Lx::Timer interface **
*************************/
void add(void *timer, Type type)
{
Context *t = nullptr;
if (type == HR)
t = new (&_timer_alloc) Context(static_cast<hrtimer *>(timer));
else
t = new (&_timer_alloc) Context(static_cast<timer_list *>(timer));
_list.append(t);
}
/**
* Delete linux timer
*/
int del(struct timer_list *timer)
int del(void *timer)
{
Context *ctx = _find_context(timer);
@ -209,10 +242,7 @@ class Lx::Timer
return rv;
}
/**
* Initial scheduling of linux timer
*/
int schedule(struct timer_list *timer, unsigned long expires)
int schedule(void *timer, unsigned long expires)
{
Context *ctx = _find_context(timer);
if (!ctx) {
@ -231,15 +261,12 @@ class Lx::Timer
return rv;
}
/**
* Schedule next linux timer
*/
void schedule_next() { _program_first_timer(); }
/**
* Check if the timer is currently pending
*/
bool pending(struct timer_list const *timer)
bool pending(void const *timer)
{
Context *ctx = _find_context(timer);
if (!ctx) {
@ -249,66 +276,32 @@ class Lx::Timer
return ctx->pending;
}
Context *find(struct timer_list const *timer) {
return _find_context(timer); }
/**
* Update jiffie counter
*/
void update_jiffies()
bool find(void const *timer) const
{
_jiffies = msecs_to_jiffies(_timer_conn.elapsed_ms());
for (Context const *c = _list.first(); c; c = c->next())
if (c->timer == timer)
return true;
return false;
}
/**
* Get first timer context
*/
Context* first() { return _list.first(); }
unsigned long jiffies() const { return _jiffies; }
void update_jiffies() {
_jiffies = msecs_to_jiffies(_timer_conn.elapsed_ms()); }
};
/******************************
** Lx::Timer implementation **
******************************/
Lx::Timer &Lx::timer(Server::Entrypoint *ep, unsigned long *jiffies)
{
static Lx_kit::Timer inst(*ep, *jiffies);
return inst;
}
void Lx::timer_update_jiffies()
{
timer().update_jiffies();
}
void Lx::run_timer(void *)
{
Timer &t = timer();
while (1) {
Lx::scheduler().current()->block_and_schedule();
while (Lx::Timer::Context *ctx = t.first()) {
if (ctx->timeout > t.jiffies())
break;
ctx->timer->function(ctx->timer->data);
t.del(ctx->timer);
}
t.schedule_next();
}
}
Lx::Timer &Lx::_timer_impl(Server::Entrypoint *ep, unsigned long *jiffies_ptr)
{
static bool initialized = false;
if (!initialized && !ep) {
PERR("attempt to use Lx::Timer before its construction");
class Lx_timer_not_constructed { };
throw Lx_timer_not_constructed();
}
static Lx::Timer inst(*ep, *jiffies_ptr);
initialized = true;
return inst;
}
#endif /* _LX_EMUL__IMPL__INTERNAL__TIMER_H_ */

View File

@ -6,32 +6,35 @@
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
* Copyright (C) 2015-2016 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 _LX_EMUL__IMPL__INTERNAL__WORK_H_
#define _LX_EMUL__IMPL__INTERNAL__WORK_H_
/* Genode includes */
#include <base/tslab.h>
#include <lx_kit/internal/list.h>
#include <lx_kit/scheduler.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/task.h>
#include <lx_emul/impl/internal/list.h>
#include <lx_emul.h>
namespace Lx {
class Work;
}
#include <lx_kit/work.h>
class Lx::Work
namespace Lx_kit { class Work; }
class Lx_kit::Work : public Lx::Work
{
public:
/**
* Context encapsulates a normal work item
*/
struct Context : public Lx::List<Context>::Element
struct Context : public Lx_kit::List<Context>::Element
{
void *work;
enum Type { NORMAL, DELAYED, TASKLET } type;
@ -66,50 +69,65 @@ class Lx::Work
private:
Lx::Task _task;
Lx::List<Context> _list;
Lx::Task _task;
Lx_kit::List<Context> _list;
Genode::Tslab<Context, 64 * sizeof(Context)> _work_alloc;
Work()
: _task(Work::run_work, reinterpret_cast<void*>(this), "work_queue",
Lx::Task::PRIORITY_2, Lx::scheduler()),
_work_alloc(Genode::env()->heap()) { }
public:
static Work & work_queue();
/**
* Unblock corresponding task
*/
void unblock() { _task.unblock(); }
/**
* Schedule work item
*/
template <typename WORK>
void schedule(WORK *work)
void _schedule(WORK *work)
{
Context *c = new (&_work_alloc) Context(work);
_list.append(c);
}
public:
Work(Genode::Allocator &alloc, char const *name = "work_queue")
: _task(Work::run_work, reinterpret_cast<void*>(this), name,
Lx::Task::PRIORITY_2, Lx::scheduler()),
_work_alloc(&alloc) { }
/**
* Execute all available work items
*/
void exec()
{
while (Context *c = _list.first()) {
c->exec();
_list.remove(c);
c->exec();
destroy(&_work_alloc, c);
}
}
/**
* Cancel work item
*/
static void run_work(void *wq)
{
Work *work_queue = reinterpret_cast<Work*>(wq);
while (1) {
work_queue->exec();
Lx::scheduler().current()->block_and_schedule();
}
}
/************************
** Lx::Work interface **
************************/
void unblock() { _task.unblock(); }
void schedule(struct work_struct *work) {
_schedule(work); }
void schedule_delayed(struct delayed_work *work,
unsigned long /*delay*/) {
_schedule(work); }
void schedule_tasklet(struct tasklet_struct *tasklet) {
_schedule(tasklet); }
bool cancel_work(struct work_struct *work, bool sync = false)
{
for (Context *c = _list.first(); c; c = c->next()) {
@ -126,21 +144,29 @@ class Lx::Work
return false;
}
static void run_work(void * wq)
{
Work * work_queue = reinterpret_cast<Work*>(wq);
while (1) {
work_queue->exec();
Lx::scheduler().current()->block_and_schedule();
}
}
char const *task_name() override { return _task.name(); }
};
Lx::Work & Lx::Work::work_queue()
/*****************************
** Lx::Work implementation **
*****************************/
Lx::Work & Lx::Work::work_queue(Genode::Allocator *alloc)
{
static Lx::Work work;
static Lx_kit::Work inst(*alloc);
return inst;
}
Lx::Work * Lx::Work::alloc_work_queue(Genode::Allocator *alloc, char const *name)
{
Lx::Work *work = new (alloc) Lx_kit::Work(*alloc, name);
return work;
}
#endif /* _LX_EMUL__IMPL__INTERNAL__WORK_H_ */
void Lx::Work::free_work_queue(Lx::Work *w)
{
PERR("%s: IMPLEMENT ME", __func__);
}