base: make irq_session asynchronous

second step

options: factor out common parts of irq_session_component.cc
options: use on foc arm no proxy threads

Fixes #1456
This commit is contained in:
Alexander Boettcher 2015-03-17 15:41:47 +01:00 committed by Christian Helmuth
parent e2cbc7c5b3
commit faa25e1df6
36 changed files with 872 additions and 1132 deletions

View File

@ -1,72 +0,0 @@
/*
* \brief IRQ session interface for NOVA
* \author Norman Feske
* \date 2010-01-30
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#include <base/lock.h>
#include <util/list.h>
#include <irq_session/capability.h>
namespace Genode {
class Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
private:
enum { STACK_SIZE = 4096 };
unsigned _irq_number;
Range_allocator *_irq_alloc;
Rpc_entrypoint _entrypoint;
Irq_session_capability _cap;
bool _attached;
public:
/**
* Constructor
*
* \param cap_session capability session to use
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args);
/**
* Destructor
*/
~Irq_session_component();
/**
* Return capability to this session
*
* If an initialization error occurs, returned capability is invalid.
*/
Irq_session_capability cap() const { return _cap; }
/***************************
** Irq session interface **
***************************/
void wait_for_irq();
Irq_signal signal();
};
}
#endif /* _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ */

View File

@ -22,57 +22,123 @@
#include <codezero/syscalls.h>
namespace Genode {
typedef Irq_proxy<Thread<1024 * sizeof(addr_t)> > Irq_proxy_base;
class Irq_proxy_component;
}
using namespace Genode;
/**
* Platform-specific proxy code
*/
void Irq_session_component::wait_for_irq()
class Genode::Irq_proxy_component : public Irq_proxy_base
{
using namespace Codezero;
private:
/* attach thread to IRQ when first called */
if (!_attached) {
int ret = l4_irq_control(IRQ_CONTROL_REGISTER, 0, _irq_number);
if (ret < 0) {
PERR("l4_irq_control(IRQ_CONTROL_REGISTER) returned %d", ret);
sleep_forever();
bool _irq_attached;
protected:
bool _associate() { return true; }
void _wait_for_irq()
{
using namespace Codezero;
/* attach thread to IRQ when first called */
if (!_irq_attached) {
int ret = l4_irq_control(IRQ_CONTROL_REGISTER, 0, _irq_number);
if (ret < 0) {
PERR("l4_irq_control(IRQ_CONTROL_REGISTER) returned %d", ret);
sleep_forever();
}
_irq_attached = true;
}
/* block for IRQ */
int ret = l4_irq_control(IRQ_CONTROL_WAIT, 0, _irq_number);
if (ret < 0)
PWRN("l4_irq_control(IRQ_CONTROL_WAIT) returned %d", ret);
}
_attached = true;
void _ack_irq() { }
public:
Irq_proxy_component(long irq_number)
:
Irq_proxy(irq_number),
_irq_attached(false)
{
_start();
}
};
/***************************
** IRQ session component **
***************************/
void Irq_session_component::ack_irq()
{
if (!_proxy) {
PERR("Expected to find IRQ proxy for IRQ %02x", _irq_number);
return;
}
/* block for IRQ */
int ret = l4_irq_control(IRQ_CONTROL_WAIT, 0, _irq_number);
if (ret < 0)
PWRN("l4_irq_control(IRQ_CONTROL_WAIT) returned %d", ret);
_proxy->ack_irq();
}
Irq_session_component::Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
const char *args)
:
_irq_alloc(irq_alloc),
_entrypoint(cap_session, STACK_SIZE, "irq"),
_attached(false)
_irq_alloc(irq_alloc)
{
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (!irq_alloc || (irq_number == -1)||
irq_alloc->alloc_addr(1, irq_number).is_error()) {
PERR("unavailable IRQ %lx requested", irq_number);
return;
if (irq_number == -1) {
PERR("invalid IRQ number requested");
throw Root::Unavailable();
}
/* check if IRQ thread was started before */
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
if (!_proxy) {
PERR("unavailable IRQ %lx requested", irq_number);
throw Root::Unavailable();
}
_irq_number = irq_number;
_cap = Irq_session_capability(_entrypoint.manage(this));
}
Irq_session_component::~Irq_session_component()
{
PERR("not yet implemented");
if (!_proxy) return;
if (_irq_sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
}
Irq_signal Irq_session_component::signal()
void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
{
PDBG("not implemented;");
return Irq_signal();
if (!_proxy) {
PERR("signal handler got not registered - irq thread unavailable");
return;
}
Genode::Signal_context_capability old = _irq_sigh;
if (old.valid() && !sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
_irq_sigh = sigh;
if (!old.valid() && sigh.valid())
_proxy->add_sharer(&_irq_sigh);
}

View File

@ -18,6 +18,7 @@
#include <util/arg_string.h>
/* core includes */
#include <irq_proxy.h>
#include <irq_root.h>
#include <util.h>
@ -28,101 +29,150 @@ namespace Fiasco {
#include <l4/sys/types.h>
}
namespace Genode {
typedef Irq_proxy<Thread<1024 * sizeof(addr_t)> > Irq_proxy_base;
class Irq_proxy_component;
}
using namespace Genode;
bool Irq_session_component::Irq_control_component::associate_to_irq(unsigned irq_number)
/**
* Platform-specific proxy code
*/
class Genode::Irq_proxy_component : public Irq_proxy_base
{
using namespace Fiasco;
protected:
int err;
l4_threadid_t irq_tid;
l4_umword_t dw0, dw1;
l4_msgdope_t result;
bool _associate()
{
using namespace Fiasco;
l4_make_taskid_from_irq(irq_number, &irq_tid);
int err;
l4_threadid_t irq_tid;
l4_umword_t dw0, dw1;
l4_msgdope_t result;
/* boost thread to IRQ priority */
enum { IRQ_PRIORITY = 0xC0 };
l4_make_taskid_from_irq(_irq_number, &irq_tid);
l4_sched_param_t param = {sp:{prio:IRQ_PRIORITY, small:0, state:0, time_exp:0, time_man:0}};
l4_threadid_t ext_preempter = L4_INVALID_ID;
l4_threadid_t partner = L4_INVALID_ID;
l4_sched_param_t old_param;
l4_thread_schedule(l4_myself(), param, &ext_preempter, &partner, &old_param);
/* boost thread to IRQ priority */
enum { IRQ_PRIORITY = 0xC0 };
err = l4_ipc_receive(irq_tid,
L4_IPC_SHORT_MSG, &dw0, &dw1,
L4_IPC_BOTH_TIMEOUT_0, &result);
l4_sched_param_t param = {sp:{prio:IRQ_PRIORITY, small:0, state:0,
time_exp:0, time_man:0}};
l4_threadid_t ext_preempter = L4_INVALID_ID;
l4_threadid_t partner = L4_INVALID_ID;
l4_sched_param_t old_param;
l4_thread_schedule(l4_myself(), param, &ext_preempter, &partner,
&old_param);
if (err != L4_IPC_RETIMEOUT) PERR("IRQ association failed");
err = l4_ipc_receive(irq_tid,
L4_IPC_SHORT_MSG, &dw0, &dw1,
L4_IPC_BOTH_TIMEOUT_0, &result);
return (err == L4_IPC_RETIMEOUT);
if (err != L4_IPC_RETIMEOUT) PERR("IRQ association failed");
return (err == L4_IPC_RETIMEOUT);
}
void _wait_for_irq()
{
using namespace Fiasco;
l4_threadid_t irq_tid;
l4_umword_t dw0=0, dw1=0;
l4_msgdope_t result;
l4_make_taskid_from_irq(_irq_number, &irq_tid);
do {
l4_ipc_call(irq_tid,
L4_IPC_SHORT_MSG, 0, 0,
L4_IPC_SHORT_MSG, &dw0, &dw1,
L4_IPC_NEVER, &result);
if (L4_IPC_IS_ERROR(result))
PERR("Ipc error %lx", L4_IPC_ERROR(result));
} while (L4_IPC_IS_ERROR(result));
}
void _ack_irq() { }
public:
Irq_proxy_component(long irq_number)
:
Irq_proxy(irq_number)
{
_start();
}
};
/***************************
** IRQ session component **
***************************/
void Irq_session_component::ack_irq()
{
if (!_proxy) {
PERR("Expected to find IRQ proxy for IRQ %02x", _irq_number);
return;
}
_proxy->ack_irq();
}
void Irq_session_component::wait_for_irq()
{
using namespace Fiasco;
l4_threadid_t irq_tid;
l4_umword_t dw0=0, dw1=0;
l4_msgdope_t result;
l4_make_taskid_from_irq(_irq_number, &irq_tid);
do {
l4_ipc_call(irq_tid,
L4_IPC_SHORT_MSG, 0, 0,
L4_IPC_SHORT_MSG, &dw0, &dw1,
L4_IPC_NEVER, &result);
if (L4_IPC_IS_ERROR(result)) PERR("Ipc error %lx", L4_IPC_ERROR(result));
} while (L4_IPC_IS_ERROR(result));
}
Irq_session_component::Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
const char *args)
:
_irq_alloc(irq_alloc),
_ep(cap_session, STACK_SIZE, "irqctrl"),
_control_cap(_ep.manage(&_control_component)),
_control_client(_control_cap)
_irq_alloc(irq_alloc)
{
bool shared = Arg_string::find_arg(args, "irq_shared").bool_value(false);
if (shared) {
PWRN("IRQ sharing not supported");
throw Root::Invalid_args();
}
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (irq_number == -1 || !irq_alloc ||
irq_alloc->alloc_addr(1, irq_number).is_error()) {
PERR("Unavailable IRQ %lx requested", irq_number);
throw Root::Invalid_args();
if (irq_number == -1) {
PERR("invalid IRQ number requested");
throw Root::Unavailable();
}
/* check if IRQ thread was started before */
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
if (!_proxy) {
PERR("unavailable IRQ %lx requested", irq_number);
throw Root::Unavailable();
}
_irq_number = irq_number;
if (!_control_client.associate_to_irq(irq_number)) {
PWRN("IRQ association failed");
throw Root::Invalid_args();
}
/* initialize capability */
_irq_cap = Irq_session_capability(_ep.manage(this));
}
Irq_session_component::~Irq_session_component()
{
PERR("Implement me, immediately!");
if (!_proxy) return;
if (_irq_sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
}
Irq_signal Irq_session_component::signal()
void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
{
PDBG("not implemented;");
return Irq_signal();
if (!_proxy) {
PERR("signal handler got not registered - irq thread unavailable");
return;
}
Genode::Signal_context_capability old = _irq_sigh;
if (old.valid() && !sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
_irq_sigh = sigh;
if (!old.valid() && sigh.valid())
_proxy->add_sharer(&_irq_sigh);
}

View File

@ -4,6 +4,5 @@ LD_TEXT_ADDR = 0x80100000
REQUIRES += arm foc_arndale
SRC_CC += arm/platform_arm.cc
INC_DIR += $(REP_DIR)/src/core/include/arm
vpath platform_services.cc $(GEN_CORE_DIR)

View File

@ -2,7 +2,6 @@ include $(PRG_DIR)/../target.inc
REQUIRES += arm foc_imx53
SRC_CC += arm/platform_arm.cc
INC_DIR += $(REP_DIR)/src/core/include/arm
LD_TEXT_ADDR = 0x70140000

View File

@ -1,29 +0,0 @@
/**
* \brief Base class for shared interrupts on ARM
* \author Sebastian Sumpf
* \date 2012-10-05
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__ARM__IRQ_PROXY_COMPONENT_H_
#define _CORE__INCLUDE__ARM__IRQ_PROXY_COMPONENT_H_
#include <irq_proxy.h>
namespace Genode {
/**
* On ARM we disable shared interrupts
*/
typedef Irq_proxy_single Irq_proxy_base;
}
#endif /* _CORE__INCLUDE__ARM__IRQ_PROXY_COMPONENT_H_ */

View File

@ -1,78 +0,0 @@
/*
* \brief IRQ session interface for Fiasco.OC
* \author Stefan Kalkowski
* \date 2011-01-28
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#include <base/lock.h>
#include <base/semaphore.h>
#include <base/rpc_server.h>
#include <util/list.h>
#include <irq_session/capability.h>
namespace Genode {
class Irq_proxy_component;
class Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
private:
/*
* Each IRQ session uses a dedicated server activation
*/
enum { STACK_SIZE = 2048 };
Rpc_entrypoint _ep;
Irq_session_capability _irq_cap;
Irq_proxy_component *_proxy;
public:
/**
* Constructor
*
* \param cap_session capability session to use
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args);
/**
* Destructor
*/
~Irq_session_component();
/**
* Return capability to this session
*
* If an initialization error occurs, returned capability is invalid.
*/
Irq_session_capability cap() const { return _irq_cap; }
/***************************
** Irq session interface **
***************************/
void wait_for_irq();
Irq_signal signal();
};
}
#endif /* _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ */

View File

@ -1,24 +0,0 @@
/**
* \brief Base class for shared interrupts on x86
* \author Sebastian Sumpf
* \date 2012-10-05
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__X86__IRQ_PROXY_COMPONENT_H_
#define _CORE__INCLUDE__X86__IRQ_PROXY_COMPONENT_H_
#include <irq_proxy.h>
namespace Genode {
typedef Irq_proxy<Thread<1024 * sizeof(addr_t)> > Irq_proxy_base;
}
#endif /* _CORE__INCLUDE__X86__IRQ_PROXY_COMPONENT_H_ */

View File

@ -21,7 +21,6 @@
/* core includes */
#include <irq_root.h>
#include <irq_proxy_component.h>
#include <irq_session_component.h>
#include <platform.h>
#include <util.h>
@ -39,6 +38,7 @@ using namespace Genode;
namespace Genode {
class Interrupt_handler;
class Irq_proxy_component;
typedef Irq_proxy<Thread<1024 * sizeof(addr_t)> > Irq_proxy_base;
}
/**
@ -69,10 +69,10 @@ class Genode::Irq_proxy_component : public Irq_proxy_base
{
private:
Cap_index *_cap;
Semaphore _sem;
long _trigger; /* interrupt trigger */
long _polarity; /* interrupt polarity */
Cap_index *_cap;
Semaphore _sem;
Irq_session::Trigger _trigger; /* interrupt trigger */
Irq_session::Polarity _polarity; /* interrupt polarity */
Native_thread _capability() const { return _cap->kcap(); }
@ -123,107 +123,162 @@ class Genode::Irq_proxy_component : public Irq_proxy_base
:
Irq_proxy_base(irq_number),
_cap(cap_map()->insert(platform_specific()->cap_id_alloc()->alloc())),
_sem(), _trigger(-1), _polarity(-1) { }
Semaphore *semaphore() { return &_sem; }
void start(long trigger, long polarity)
_sem(), _trigger(Irq_session::TRIGGER_UNCHANGED),
_polarity(Irq_session::POLARITY_UNCHANGED)
{
_trigger = trigger;
_polarity = polarity;
_start();
}
bool match_mode(long trigger, long polarity)
Semaphore *semaphore() { return &_sem; }
Irq_session::Trigger trigger() const { return _trigger; }
Irq_session::Polarity polarity() const { return _polarity; }
void setup_irq_mode(Irq_session::Trigger t, Irq_session::Polarity p)
{
if (trigger == Irq_session::TRIGGER_UNCHANGED &&
polarity == Irq_session::POLARITY_UNCHANGED)
return true;
_trigger = t;
_polarity = p;
if (_trigger < 0 && _polarity < 0)
return true;
return _trigger == trigger && _polarity == polarity;
/* set interrupt mode */
Platform::setup_irq_mode(_irq_number, _trigger, _polarity);
}
long trigger() const { return _trigger; }
long polarity() const { return _polarity; }
};
/********************************
** IRQ session implementation **
********************************/
/***************************
** IRQ session component **
***************************/
Irq_session_component::Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args)
:
_ep(cap_session, STACK_SIZE, "irqctrl"),
_proxy(0)
void Irq_session_component::ack_irq()
{
using namespace Fiasco;
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (irq_number == -1) {
PERR("Unavailable IRQ %lx requested", irq_number);
throw Root::Invalid_args();
if (!_proxy) {
PERR("Expected to find IRQ proxy for IRQ %02x", _irq_number);
return;
}
long irq_trigger = Arg_string::find_arg(args, "irq_trigger").long_value(-1);
irq_trigger = irq_trigger == -1 ? 0 : irq_trigger;
_proxy->ack_irq();
}
long irq_polarity = Arg_string::find_arg(args, "irq_polarity").long_value(-1);
irq_polarity = irq_polarity == -1 ? 0 : irq_polarity;
Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
const char *args)
{
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (irq_number == -1) {
PERR("invalid IRQ number requested");
throw Root::Unavailable();
}
long irq_t = Arg_string::find_arg(args, "irq_trigger").long_value(-1);
long irq_p = Arg_string::find_arg(args, "irq_polarity").long_value(-1);
Irq_session::Trigger irq_trigger;
Irq_session::Polarity irq_polarity;
switch(irq_t) {
case -1:
case Irq_session::TRIGGER_UNCHANGED:
irq_trigger = Irq_session::TRIGGER_UNCHANGED;
break;
case Irq_session::TRIGGER_EDGE:
irq_trigger = Irq_session::TRIGGER_EDGE;
break;
case Irq_session::TRIGGER_LEVEL:
irq_trigger = Irq_session::TRIGGER_LEVEL;
break;
default:
throw Root::Unavailable();
}
switch(irq_p) {
case -1:
case POLARITY_UNCHANGED:
irq_polarity = POLARITY_UNCHANGED;
break;
case POLARITY_HIGH:
irq_polarity = POLARITY_HIGH;
break;
case POLARITY_LOW:
irq_polarity = POLARITY_LOW;
break;
default:
throw Root::Unavailable();
}
/*
* temorary hack for fiasco.oc using the local-apic,
* temporary hack for fiasco.oc using the local-apic,
* where old pic-line 0 maps to 2
*/
if (irq_number == 0)
irq_number = 2;
if (!(_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number,
irq_alloc))) {
PERR("No proxy for IRQ %lu found", irq_number);
/* check if IRQ thread was started before */
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
if (!_proxy) {
PERR("unavailable IRQ %lx requested", irq_number);
throw Root::Unavailable();
}
bool setup = false;
bool fail = false;
/* sanity check */
if (!_proxy->match_mode(irq_trigger, irq_polarity)) {
PERR("Interrupt mode mismatch: IRQ %ld current mode: t: %ld p: %ld"
"request mode: trg: %ld p: %ld",
if (irq_trigger != TRIGGER_UNCHANGED && _proxy->trigger() != irq_trigger) {
if (_proxy->trigger() == TRIGGER_UNCHANGED)
setup = true;
else
fail = true;
}
if (irq_polarity != POLARITY_UNCHANGED && _proxy->polarity() != irq_polarity) {
if (_proxy->polarity() == POLARITY_UNCHANGED)
setup = true;
else
fail = true;
}
if (fail) {
PERR("Interrupt mode mismatch: IRQ %ld current mode: t: %d p: %d "
"request mode: trg: %d p: %d",
irq_number, _proxy->trigger(), _proxy->polarity(),
irq_trigger, irq_polarity);
throw Root::Unavailable();
}
/* set interrupt mode and start proxy */
_proxy->start(irq_trigger, irq_polarity);
if (setup)
/* set interrupt mode */
_proxy->setup_irq_mode(irq_trigger, irq_polarity);
if (!_proxy->add_sharer())
throw Root::Unavailable();
/* initialize capability */
_irq_cap = _ep.manage(this);
_irq_number = irq_number;
}
void Irq_session_component::wait_for_irq()
Irq_session_component::~Irq_session_component()
{
_proxy->wait_for_irq();
if (!_proxy) return;
if (_irq_sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
}
Irq_session_component::~Irq_session_component() {
_proxy->remove_sharer(); }
Irq_signal Irq_session_component::signal()
void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
{
PDBG("not implemented;");
return Irq_signal();
if (!_proxy) {
PERR("signal handler got not registered - irq thread unavailable");
return;
}
Genode::Signal_context_capability old = _irq_sigh;
if (old.valid() && !sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
_irq_sigh = sigh;
if (!old.valid() && sigh.valid())
_proxy->add_sharer(&_irq_sigh);
}

View File

@ -4,6 +4,5 @@ LD_TEXT_ADDR = 0x80140000
REQUIRES += arm foc_panda
SRC_CC += arm/platform_arm.cc
INC_DIR += $(REP_DIR)/src/core/include/arm
vpath platform_services.cc $(GEN_CORE_DIR)

View File

@ -2,7 +2,6 @@ include $(PRG_DIR)/../target.inc
REQUIRES += arm foc_pbxa9
SRC_CC += arm/platform_arm.cc
INC_DIR += $(REP_DIR)/src/core/include/arm
LD_TEXT_ADDR = 0x70490000

View File

@ -2,7 +2,6 @@ include $(PRG_DIR)/../target.inc
REQUIRES += arm foc_vea9x4
SRC_CC += arm/platform_arm.cc
INC_DIR += $(REP_DIR)/src/core/include/arm
LD_TEXT_ADDR = 0x60490000

View File

@ -5,7 +5,5 @@ REQUIRES += x86
SRC_CC += io_port_session_component.cc \
x86/platform_x86.cc
INC_DIR += $(REP_DIR)/src/core/include/x86
vpath io_port_session_component.cc $(GEN_CORE_DIR)/x86
vpath platform_services.cc $(GEN_CORE_DIR)/x86

View File

@ -207,12 +207,10 @@ namespace Kernel
* Await any context of a receiver and optionally ack a context before
*
* \param receiver_id kernel name of the targeted signal receiver
* \param context_id kernel name of a context that shall be acknowledged
*
* \retval 0 suceeded
* \retval -1 failed
*
* If context is set to 0, the call doesn't acknowledge any context.
* If this call returns 0, an instance of 'Signal::Data' is located at the
* base of the callers UTCB. Every occurence of a signal is provided
* through this function until it gets delivered through this function or
@ -223,10 +221,9 @@ namespace Kernel
* deliver again unless its last delivery has been acknowledged via
* ack_signal.
*/
inline int await_signal(unsigned const receiver_id,
unsigned const context_id)
inline int await_signal(unsigned const receiver_id)
{
return call(call_id_await_signal(), receiver_id, context_id);
return call(call_id_await_signal(), receiver_id);
}

View File

@ -1,23 +0,0 @@
/*
* \brief Client-side IRQ session interface - specific for base-hw
* \author Martin Stein
* \date 2013-10-24
*/
/*
* Copyright (C) 2013-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.
*/
#include <irq_session/client.h>
void Genode::Irq_session_client::wait_for_irq()
{
while (Kernel::await_signal(irq_signal.receiver_id,
irq_signal.context_id))
{
PERR("failed to receive interrupt");
}
}

View File

@ -189,7 +189,7 @@ bool Signal_receiver::pending() { return Kernel::signal_pending(_cap.dst()); }
Signal Signal_receiver::wait_for_signal()
{
/* await a signal */
if (Kernel::await_signal(_cap.dst(), 0)) {
if (Kernel::await_signal(_cap.dst())) {
PERR("failed to receive signal");
return Signal(Signal::Data());
}

View File

@ -5,71 +5,59 @@
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
* Copyright (C) 2013-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 _INCLUDE__IRQ_SESSION_COMPONENT_H_
#define _INCLUDE__IRQ_SESSION_COMPONENT_H_
#define __INCLUDE__IRQ_SESSION_COMPONENT_H_
/* Genode includes */
#include <base/rpc_server.h>
#include <util/list.h>
#include <irq_session/capability.h>
namespace Genode
{
/**
* Backend for IRQ sessions to core
*/
class Irq_session_component
:
public Rpc_object<Irq_session, Irq_session_component>,
public List<Irq_session_component>::Element
{
private:
Range_allocator * const _irq_alloc;
Irq_session_capability _cap;
Irq_signal _signal;
Genode::uint8_t _kernel_object[sizeof(Kernel::User_irq)];
public:
/**
* Constructor
*
* \param cap_session capability session to use
* \param irq_alloc interrupt allocator
* \param args session construction arguments
*/
Irq_session_component(Cap_session * const cap_session,
Range_allocator * const irq_alloc,
const char * const args);
/**
* Destructor
*/
~Irq_session_component();
/**
* Return capability to this session
*
* If an initialization error occurs, returned _cap is invalid.
*/
Irq_session_capability cap() const { return _cap; }
/*****************
** Irq_session **
*****************/
void wait_for_irq();
Irq_signal signal();
};
namespace Genode {
class Irq_session_component;
}
class Genode::Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
private:
unsigned _irq_number;
Range_allocator *_irq_alloc;
Genode::uint8_t _kernel_object[sizeof(Kernel::User_irq)];
Signal_context_capability _sig_cap;
unsigned _find_irq_number(const char * const args);
public:
/**
* Constructor
*
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Range_allocator *irq_alloc,
const char *args);
/**
* Destructor
*/
~Irq_session_component();
/***************************
** Irq session interface **
***************************/
void ack_irq();
void sigh(Signal_context_capability) override;
};
#endif /* _INCLUDE__IRQ_SESSION_COMPONENT_H_ */

View File

@ -353,12 +353,14 @@ namespace Kernel
/**
* Create an interrupt object
*
* \param p memory donation for the irq object
* \param irq_nr interrupt number
* \param p memory donation for the irq object
* \param irq_nr interrupt number
* \param signal_context_id kernel name of the signal context
*/
inline void new_irq(addr_t const p, unsigned irq_nr)
inline int new_irq(addr_t const p, unsigned irq_nr,
unsigned signal_context_id)
{
call(call_id_new_irq(), (Call_arg) p, irq_nr);
return call(call_id_new_irq(), (Call_arg) p, irq_nr, signal_context_id);
}
/**

View File

@ -47,8 +47,14 @@ namespace Genode
class Kernel::Irq : public Object_pool<Irq>::Item
{
public:
using Pool = Object_pool<Irq>;
protected:
Pool &_pool;
/**
* Get kernel name of the interrupt
*/
@ -56,16 +62,6 @@ class Kernel::Irq : public Object_pool<Irq>::Item
public:
using Pool = Object_pool<Irq>;
/**
* Constructor
*
* \param irq_id kernel name of the interrupt
*/
Irq(unsigned const irq_id)
: Pool::Item(irq_id) { }
/**
* Constructor
*
@ -73,14 +69,9 @@ class Kernel::Irq : public Object_pool<Irq>::Item
* \param pool pool this interrupt shall belong to
*/
Irq(unsigned const irq_id, Pool &pool)
: Irq(irq_id) { pool.insert(this); }
: Pool::Item(irq_id), _pool(pool) { _pool.insert(this); }
/**
* Destructor
*
* By now, there is no use case to destruct interrupts
*/
virtual ~Irq() { PERR("destruction of interrupts not implemented"); }
virtual ~Irq() { _pool.remove(this); }
/**
* Handle occurence of the interrupt
@ -102,12 +93,12 @@ class Kernel::Irq : public Object_pool<Irq>::Item
class Kernel::User_irq
:
public Kernel::Irq,
public Signal_receiver,
public Signal_context,
public Signal_ack_handler
{
private:
Signal_context &_context;
/**
* Get map that provides all user interrupts by their kernel names
*/
@ -127,30 +118,25 @@ class Kernel::User_irq
*
* \param irq_id kernel name of the interrupt
*/
User_irq(unsigned const irq_id)
: Irq(irq_id), Signal_context(this, 0)
User_irq(unsigned const irq_id, Signal_context &context)
: Irq(irq_id, *_pool()), _context(context)
{
_pool()->insert(this);
disable();
Signal_context::ack_handler(this);
_context.ack_handler(this);
}
/**
* Get kernel name of the interrupt-signal receiver
*/
unsigned receiver_id() const { return Signal_receiver::Object::id(); }
/**
* Get kernel name of the interrupt-signal context
*/
unsigned context_id() const { return Signal_context::Object::id(); }
~User_irq()
{
_context.ack_handler(nullptr);
disable();
}
/**
* Handle occurence of the interrupt
*/
void occurred()
{
Signal_context::submit(1);
_context.submit(1);
disable();
}

View File

@ -22,64 +22,53 @@
using namespace Genode;
/**
* On other platforms, every IRQ session component creates its entrypoint.
* However, on base-hw this isn't necessary as users can wait for their
* interrupts directly. Instead of replacing cores generic irq_root.h and
* main.cc with base-hw specific versions, we simply use a local singleton.h
*/
static Rpc_entrypoint * irq_session_ep()
unsigned Irq_session_component::_find_irq_number(const char * const args)
{
enum { STACK_SIZE = 2048 };
static Rpc_entrypoint
_ep(core_env()->cap_session(), STACK_SIZE, "irq_session_ep");
return &_ep;
return Arg_string::find_arg(args, "irq_number").long_value(-1);
}
void Irq_session_component::wait_for_irq() { PERR("not implemented"); }
Irq_signal Irq_session_component::signal() { return _signal; }
void Irq_session_component::ack_irq()
{
Kernel::ack_signal(_sig_cap.dst());
}
void Irq_session_component::sigh(Signal_context_capability cap)
{
if (_sig_cap.valid()) {
PWRN("signal handler already registered for IRQ %u", _irq_number);
return;
}
_sig_cap = cap;
if (Kernel::new_irq((addr_t)&_kernel_object, _irq_number, _sig_cap.dst()))
PWRN("invalid signal handler for IRQ %u", _irq_number);
}
Irq_session_component::~Irq_session_component()
{
using namespace Kernel;
irq_session_ep()->dissolve(this);
User_irq * kirq = reinterpret_cast<User_irq*>(&_kernel_object);
_irq_alloc->free((void *)(addr_t)static_cast<Kernel::Irq*>(kirq)->id());
Kernel::delete_irq(kirq);
if (_sig_cap.valid())
Kernel::delete_irq(kirq);
}
Irq_session_component::Irq_session_component(Cap_session * const cap_session,
Range_allocator * const irq_alloc,
const char * const args)
: _irq_alloc(irq_alloc)
Irq_session_component::Irq_session_component(Range_allocator * const irq_alloc,
const char * const args)
:
_irq_number(Platform::irq(_find_irq_number(args))),
_irq_alloc(irq_alloc)
{
using namespace Kernel;
/* check arguments */
bool shared = Arg_string::find_arg(args, "irq_shared").bool_value(false);
if (shared) {
PERR("shared interrupts not supported");
throw Root::Invalid_args();
}
/* allocate interrupt */
long irq_nr = Arg_string::find_arg(args, "irq_number").long_value(-1);
bool error = irq_nr < 0 || !_irq_alloc;
/* enable platform specific code to apply mappings */
long const plat_irq_nr = Platform::irq(irq_nr);
error |= _irq_alloc->alloc_addr(1, plat_irq_nr).is_error();
if (error) {
if (_irq_alloc->alloc_addr(1, _irq_number).is_error()) {
PERR("unavailable interrupt requested");
throw Root::Invalid_args();
}
/* make interrupt accessible */
new_irq((addr_t)&_kernel_object, plat_irq_nr);
User_irq * kirq = reinterpret_cast<User_irq*>(&_kernel_object);
_signal = { kirq->receiver_id(), kirq->context_id() };
_cap = Irq_session_capability(irq_session_ep()->manage(this));
}

View File

@ -582,13 +582,6 @@ void Thread::_call_new_signal_context()
void Thread::_call_await_signal()
{
/* check wether to acknowledge a context */
unsigned const context_id = user_arg_2();
if (context_id) {
Signal_context * const c = Signal_context::pool()->object(context_id);
if (c) { c->ack(); }
else { PWRN("failed to acknowledge signal context"); }
}
/* lookup receiver */
unsigned const receiver_id = user_arg_1();
Signal_receiver * const r = Signal_receiver::pool()->object(receiver_id);
@ -688,8 +681,19 @@ void Thread::_call_delete_signal_receiver() {
reinterpret_cast<Signal_receiver*>(user_arg_1())->~Signal_receiver(); }
void Thread::_call_new_irq() {
new ((void *)user_arg_1()) User_irq(user_arg_2()); }
void Thread::_call_new_irq()
{
Signal_context * const c = Signal_context::pool()->object(user_arg_3());
if (!c) {
PWRN("%s -> %s: invalid signal context for interrupt",
pd_label(), label());
user_arg_0(-1);
return;
}
new ((void *)user_arg_1()) User_irq(user_arg_2(), *c);
user_arg_0(0);
}
void Thread::_call_delete_irq() {

View File

@ -49,7 +49,7 @@ extern Genode::addr_t _vt_host_context_ptr;
struct Kernel::Vm_irq : Kernel::Irq
{
Vm_irq(unsigned const irq) : Kernel::Irq(irq) {}
Vm_irq(unsigned const irq) : Kernel::Irq(irq, *cpu_pool()->executing_cpu()) {}
/**
* A VM interrupt gets injected into the VM scheduled on the current CPU
@ -180,10 +180,6 @@ struct Kernel::Virtual_timer
void Kernel::prepare_hypervisor()
{
Cpu * cpu = cpu_pool()->executing_cpu();
cpu->insert(&Virtual_timer::timer().irq);
cpu->insert(&Virtual_pic::pic().irq);
/* set hypervisor exception vector */
Cpu::hyp_exception_entry_at(&_vt_host_entry);

View File

@ -20,6 +20,7 @@ SRC_CC += env/rm_session_mmap.cc env/debug.cc
SRC_CC += signal/signal.cc signal/common.cc signal/platform.cc
SRC_CC += server/server.cc server/common.cc
SRC_CC += thread/trace.cc thread/thread_env.cc thread/context_allocator.cc
SRC_CC += irq/platform.cc
INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock
INC_DIR += $(REP_DIR)/src/base/ipc

View File

@ -15,46 +15,38 @@
#define _CORE__INCLUDE__LINUX__IRQ_SESSION_COMPONENT_H_
#include <util/list.h>
#include <base/lock.h>
#include <base/rpc_server.h>
#include <irq_session/irq_session.h>
namespace Genode {
class Irq_session_component : public List<Irq_session_component>::Element
{
public:
/**
* Constructor
*
* \param cap_session capability session to use
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args) { }
/**
* Destructor
*/
~Irq_session_component() { }
/**
* Return capability to this session
*
* Capability is always invalid under Linux.
*/
Session_capability cap() const { return Session_capability(); }
/***************************
** Irq session interface **
***************************/
void wait_for_irq() { }
};
class Irq_session_component;
}
class Genode::Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
public:
/**
* Constructor
*
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Range_allocator *irq_alloc,
const char *args) { }
/**
* Destructor
*/
~Irq_session_component() { }
/***************************
** Irq session interface **
***************************/
void ack_irq() { }
void sigh(Signal_context_capability) override { }
};
#endif /* _CORE__INCLUDE__LINUX__IRQ_SESSION_COMPONENT_H_ */

View File

@ -1,75 +0,0 @@
/*
* \brief IRQ session interface for NOVA
* \author Norman Feske
* \date 2010-01-30
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#include <base/lock.h>
#include <base/rpc_server.h>
#include <util/list.h>
#include <irq_session/capability.h>
namespace Genode {
class Irq_proxy_component;
class Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
private:
/*
* Each IRQ session uses a dedicated server activation
*/
enum { STACK_SIZE = 2048 };
Rpc_entrypoint _ep;
Irq_session_capability _irq_cap;
Irq_proxy_component *_proxy;
public:
/**
* Constructor
*
* \param cap_session capability session to use
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args);
/**
* Destructor
*/
~Irq_session_component();
/**
* Return capability to this session
*
* If an initialization error occurs, returned capability is invalid.
*/
Irq_session_capability cap() const { return _irq_cap; }
/***************************
** Irq session interface **
***************************/
void wait_for_irq();
Irq_signal signal();
};
}
#endif /* _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ */

View File

@ -170,43 +170,68 @@ class Genode::Irq_proxy_component : public Irq_proxy<Irq_thread>
};
typedef Irq_proxy<Irq_thread> Proxy;
void Irq_session_component::wait_for_irq()
/***************************
** IRQ session component **
***************************/
void Irq_session_component::ack_irq()
{
_proxy->wait_for_irq();
/* interrupt ocurred and proxy woke us up */
if (!_proxy) {
PERR("Expected to find IRQ proxy for IRQ %02x", _irq_number);
return;
}
_proxy->ack_irq();
}
Irq_session_component::Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
const char *args)
:
_ep(cap_session, STACK_SIZE, "irq")
{
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
/* check if IRQ thread was started before */
_proxy = Proxy::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
if (irq_number == -1 || !_proxy) {
PERR("Unavailable IRQ %lx requested", irq_number);
if (irq_number == -1) {
PERR("invalid IRQ number requested");
throw Root::Unavailable();
}
_proxy->add_sharer();
/* check if IRQ thread was started before */
typedef Irq_proxy<Irq_thread> Proxy;
_proxy = Proxy::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
if (!_proxy) {
PERR("unavailable IRQ %lx requested", irq_number);
throw Root::Unavailable();
}
/* initialize capability */
_irq_cap = _ep.manage(this);
_irq_number = irq_number;
}
Irq_session_component::~Irq_session_component() { }
Irq_signal Irq_session_component::signal()
Irq_session_component::~Irq_session_component()
{
PDBG("not implemented;");
return Irq_signal();
if (_proxy) return;
if (_irq_sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
}
void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
{
if (!_proxy) {
PERR("signal handler got not registered - irq thread unavailable");
return;
}
Genode::Signal_context_capability old = _irq_sigh;
if (old.valid() && !sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
_irq_sigh = sigh;
if (!old.valid() && sigh.valid())
_proxy->add_sharer(&_irq_sigh);
}

View File

@ -12,10 +12,12 @@
* under the terms of the GNU General Public License version 2.
*/
#include <irq_proxy.h>
/* Genode includes */
#include <base/printf.h>
#include <util/arg_string.h>
/* core includes */
#include <irq_root.h>
#include <irq_session_component.h>
/* OKL4 includes */
namespace Okl4 { extern "C" {
@ -30,12 +32,6 @@ using namespace Okl4;
using namespace Genode;
/**
* Proxy class with generic thread
*/
typedef Irq_proxy<Thread<0x1000> > Proxy;
/* XXX move this functionality to a central place instead of duplicating it */
static inline Okl4::L4_ThreadId_t thread_get_my_global_id()
{
@ -44,11 +40,15 @@ static inline Okl4::L4_ThreadId_t thread_get_my_global_id()
return myself;
}
namespace Genode {
typedef Irq_proxy<Thread<1024 * sizeof(addr_t)> > Irq_proxy_base;
class Irq_proxy_component;
}
/**
* Platform-specific proxy code
*/
class Irq_proxy_component : public Proxy
class Genode::Irq_proxy_component : public Irq_proxy_base
{
protected:
@ -80,13 +80,14 @@ class Irq_proxy_component : public Proxy
/* prepare ourself to receive asynchronous IRQ notifications */
L4_Set_NotifyMask(1 << IRQ_NOTIFY_BIT);
L4_Accept(L4_NotifyMsgAcceptor);
return true;
}
void _wait_for_irq()
{
L4_Accept(L4_NotifyMsgAcceptor);
/* wait for asynchronous interrupt notification */
L4_ThreadId_t partner = L4_nilthread;
L4_ReplyWait(partner, &partner);
@ -111,35 +112,23 @@ class Irq_proxy_component : public Proxy
** IRQ session component **
***************************/
bool Irq_session_component::Irq_control_component::associate_to_irq(unsigned irq)
{
return true;
}
void Irq_session_component::wait_for_irq()
void Irq_session_component::ack_irq()
{
/* block at interrupt proxy */
Proxy *p = Proxy::get_irq_proxy<Irq_proxy_component>(_irq_number);
if (!p) {
if (!_proxy) {
PERR("Expected to find IRQ proxy for IRQ %02x", _irq_number);
return;
}
p->wait_for_irq();
/* interrupt ocurred and proxy woke us up */
_proxy->ack_irq();
}
Irq_session_component::Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
const char *args)
:
_irq_alloc(irq_alloc),
_ep(cap_session, STACK_SIZE, "irqctrl"),
_irq_attached(false),
_control_client(Capability<Irq_session_component::Irq_control>())
_irq_alloc(irq_alloc)
{
/*
* XXX Removed irq_shared argument as this is the default now. If we need
@ -154,30 +143,39 @@ Irq_session_component::Irq_session_component(Cap_session *cap_session,
}
/* check if IRQ thread was started before */
Proxy *irq_proxy = Proxy::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
if (!irq_proxy) {
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
if (!_proxy) {
PERR("unavailable IRQ %lx requested", irq_number);
throw Root::Unavailable();
}
irq_proxy->add_sharer();
_irq_number = irq_number;
/* initialize capability */
_irq_cap = _ep.manage(this);
}
Irq_session_component::~Irq_session_component()
{
PERR("not yet implemented");
/* TODO del_sharer() resp. put_sharer() */
if (!_proxy) return;
if (_irq_sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
}
Irq_signal Irq_session_component::signal()
void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
{
PDBG("not implemented;");
return Irq_signal();
if (!_proxy) {
PERR("signal handler got not registered - irq thread unavailable");
return;
}
Genode::Signal_context_capability old = _irq_sigh;
if (old.valid() && !sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
_irq_sigh = sigh;
if (!old.valid() && sigh.valid())
_proxy->add_sharer(&_irq_sigh);
}

View File

@ -18,6 +18,7 @@
#include <util/arg_string.h>
/* core includes */
#include <irq_proxy.h>
#include <irq_root.h>
#include <util.h>
@ -39,102 +40,161 @@ static inline L4_ThreadId_t irqno_to_threadid(unsigned int irqno)
}
bool Irq_session_component::Irq_control_component::associate_to_irq(unsigned)
{
/*
* We defer the association with the IRQ to the first call of the
* 'wait_for_irq' function.
*/
return true;
namespace Genode {
typedef Irq_proxy<Thread<1024 * sizeof(addr_t)> > Irq_proxy_base;
class Irq_proxy_component;
}
void Irq_session_component::wait_for_irq()
/**
* Platform-specific proxy code
*/
class Genode::Irq_proxy_component : public Irq_proxy_base
{
L4_ThreadId_t irq_thread = irqno_to_threadid(_irq_number);
private:
/* attach to IRQ when called for the first time */
L4_MsgTag_t res;
if (!_irq_attached) {
/*
* On Pistachio, an IRQ is unmasked right after attaching.
* Hence, the kernel may send an IRQ IPC when the IRQ hander is
* not explicitly waiting for an IRQ but when it is waiting for
* a client's 'wait_for_irq' RPC call. To avoid this conflict, we
* lazily associate to the IRQ when calling the 'wait_for_irq'
* function for the first time. We use the '_irq_attached' flag
* for detecting the first call.
*/
bool _irq_attached; /* true if IRQ is already attached */
if (L4_AssociateInterrupt(irq_thread, L4_Myself()) != true) {
PERR("L4_AssociateInterrupt failed");
return;
protected:
bool _associate() { return true; }
void _wait_for_irq()
{
L4_ThreadId_t irq_thread = irqno_to_threadid(_irq_number);
/* attach to IRQ when called for the first time */
L4_MsgTag_t res;
if (!_irq_attached) {
if (L4_AssociateInterrupt(irq_thread, L4_Myself()) != true) {
PERR("L4_AssociateInterrupt failed");
return;
}
/*
* Right after associating with an interrupt, the interrupt is
* unmasked. Hence, we do not need to send an unmask message
* to the IRQ thread but just wait for the IRQ.
*/
L4_Set_MsgTag(L4_Niltag);
res = L4_Receive(irq_thread);
/*
* Now, the IRQ is masked. To receive the next IRQ we have to send
* an unmask message to the IRQ thread first.
*/
_irq_attached = true;
/* receive subsequent interrupt */
} else {
/* send unmask message and wait for new IRQ */
L4_Set_MsgTag(L4_Niltag);
res = L4_Call(irq_thread);
}
if (L4_IpcFailed(res)) {
PERR("ipc error while waiting for interrupt.");
return;
}
}
/*
* Right after associating with an interrupt, the interrupt is
* unmasked. Hence, we do not need to send an unmask message
* to the IRQ thread but just wait for the IRQ.
*/
L4_Set_MsgTag(L4_Niltag);
res = L4_Receive(irq_thread);
void _ack_irq() { }
/*
* Now, the IRQ is masked. To receive the next IRQ we have to send
* an unmask message to the IRQ thread first.
*/
_irq_attached = true;
public:
/* receive subsequent interrupt */
} else {
Irq_proxy_component(long irq_number)
:
Irq_proxy(irq_number),
_irq_attached(false)
{
_start();
}
/* send unmask message and wait for new IRQ */
L4_Set_MsgTag(L4_Niltag);
res = L4_Call(irq_thread);
}
~Irq_proxy_component()
{
L4_ThreadId_t const thread_id = irqno_to_threadid(_irq_number);
L4_Word_t const res = L4_DeassociateInterrupt(thread_id);
if (L4_IpcFailed(res)) {
PERR("ipc error while waiting for interrupt.");
if (res != 1)
PERR("L4_DeassociateInterrupt failed");
}
};
/***************************
** IRQ session component **
***************************/
void Irq_session_component::ack_irq()
{
if (!_proxy) {
PERR("Expected to find IRQ proxy for IRQ %02x", _irq_number);
return;
}
_proxy->ack_irq();
}
Irq_session_component::Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
Irq_session_component::Irq_session_component(Range_allocator *irq_alloc,
const char *args)
:
_irq_alloc(irq_alloc),
_ep(cap_session, STACK_SIZE, "irqctrl"),
_irq_attached(false),
_control_client(Capability<Irq_session_component::Irq_control>())
_irq_alloc(irq_alloc)
{
bool shared = Arg_string::find_arg(args, "irq_shared").bool_value(false);
if (shared) {
PWRN("IRQ sharing not supported");
/* FIXME error condition -> exception */
return;
}
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (irq_number == -1 || !irq_alloc ||
irq_alloc->alloc_addr(1, irq_number).is_error()) {
PERR("unavailable IRQ %lx requested", irq_number);
if (irq_number == -1) {
PERR("invalid IRQ number requested");
/* FIXME error condition -> exception */
return;
throw Root::Unavailable();
}
_irq_number = irq_number;
/* initialize capability */
_irq_cap = _ep.manage(this);
/* check if IRQ thread was started before */
_proxy = Irq_proxy_component::get_irq_proxy<Irq_proxy_component>(irq_number, irq_alloc);
if (!_proxy) {
PERR("unavailable IRQ %lx requested", irq_number);
throw Root::Unavailable();
}
_irq_number = irq_number;
}
Irq_session_component::~Irq_session_component()
{
L4_Word_t res = L4_DeassociateInterrupt(irqno_to_threadid(_irq_number));
if (!_proxy) return;
if (res != 1) {
PERR("L4_DeassociateInterrupt failed");
}
if (_irq_sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
}
Irq_signal Irq_session_component::signal()
void Irq_session_component::sigh(Genode::Signal_context_capability sigh)
{
PDBG("not implemented;");
return Irq_signal();
if (!_proxy) {
PERR("signal handler got not registered - irq thread unavailable");
return;
}
Genode::Signal_context_capability old = _irq_sigh;
if (old.valid() && !sigh.valid())
_proxy->remove_sharer(&_irq_sigh);
_irq_sigh = sigh;
if (!old.valid() && sigh.valid())
_proxy->add_sharer(&_irq_sigh);
}

View File

@ -26,11 +26,6 @@ namespace Genode { struct Irq_session_client; }
*/
struct Genode::Irq_session_client : Rpc_client<Irq_session>
{
/*
* FIXME: This is used only client-internal and could thus be protected.
*/
Irq_signal const irq_signal;
/**
* Constructor
*
@ -38,8 +33,7 @@ struct Genode::Irq_session_client : Rpc_client<Irq_session>
*/
explicit Irq_session_client(Irq_session_capability const & session)
:
Rpc_client<Irq_session>(session),
irq_signal(signal())
Rpc_client<Irq_session>(session)
{ }
@ -47,9 +41,9 @@ struct Genode::Irq_session_client : Rpc_client<Irq_session>
** Irq_session **
*****************/
Irq_signal signal() override { return call<Rpc_signal>(); }
void ack_irq() override;
void wait_for_irq() override;
void sigh(Signal_context_capability sigh) override { call<Rpc_sigh>(sigh); }
};
#endif /* _INCLUDE__IRQ_SESSION__CLIENT_H_ */

View File

@ -21,22 +21,47 @@ namespace Genode { struct Irq_connection; }
struct Genode::Irq_connection : Connection<Irq_session>, Irq_session_client
{
/**
* Constructor
*
* \param irq physical interrupt number
* \param trigger interrupt trigger (e.g., level/edge)
* \param polarity interrupt trigger polarity (e.g., low/high)
*/
Irq_connection(unsigned irq,
Irq_session::Trigger trigger = Irq_session::TRIGGER_UNCHANGED,
Irq_session::Polarity polarity = Irq_session::POLARITY_UNCHANGED)
:
Connection<Irq_session>(
session("ram_quota=4K, irq_number=%u, irq_trigger=%u, irq_polarity=%u",
irq, trigger, polarity)),
Irq_session_client(cap())
{ }
private:
Genode::Signal_receiver _sig_rec;
Genode::Signal_context _sigh_ctx;
Genode::Signal_context_capability _sigh_cap;
public:
/**
* Constructor
*
* \param irq physical interrupt number
* \param trigger interrupt trigger (e.g., level/edge)
* \param polarity interrupt trigger polarity (e.g., low/high)
*/
Irq_connection(unsigned irq,
Irq_session::Trigger trigger = Irq_session::TRIGGER_UNCHANGED,
Irq_session::Polarity polarity = Irq_session::POLARITY_UNCHANGED)
:
Connection<Irq_session>(
session("ram_quota=4K, irq_number=%u, irq_trigger=%u, irq_polarity=%u",
irq, trigger, polarity)),
Irq_session_client(cap()),
_sigh_cap(_sig_rec.manage(&_sigh_ctx))
{
/* register default signal handler */
Irq_session_client::sigh(_sigh_cap);
}
~Irq_connection()
{
Irq_session_client::sigh(Genode::Signal_context_capability());
_sig_rec.dissolve(&_sigh_ctx);
}
/**
* Convenience function to acknowledge last IRQ and to block calling
* thread until next IRQ fires.
*/
void wait_for_irq();
};
#endif /* _INCLUDE__IRQ_SESSION__CONNECTION_H_ */

View File

@ -6,8 +6,7 @@
*
* An open IRQ session represents a valid IRQ attachment/association.
* Initially, the interrupt is masked and will only occur if enabled. This is
* done by calling wait_for_irq(). When the interrupt is delivered to the
* client, it was acknowledged and masked at the interrupt controller before.
* done by calling ack_irq().
*
* Disassociation from an IRQ is done by closing the session.
*/
@ -22,25 +21,15 @@
#ifndef _INCLUDE__IRQ_SESSION__IRQ_SESSION_H_
#define _INCLUDE__IRQ_SESSION__IRQ_SESSION_H_
#include <base/signal.h>
#include <base/capability.h>
#include <session/session.h>
namespace Genode {
struct Irq_session;
struct Irq_signal;
}
/**
* Information that enables a user to await and ack an IRQ directly
*/
struct Genode::Irq_signal
{
unsigned receiver_id;
unsigned context_id;
};
struct Genode::Irq_session : Session
{
/**
@ -59,17 +48,14 @@ struct Genode::Irq_session : Session
virtual ~Irq_session() { }
/**
* Await the next occurence of the interrupt of this session
* Acknowledge handling of last interrupt - re-enables interrupt reception
*/
virtual void wait_for_irq() = 0;
virtual void ack_irq() = 0;
/**
* Get information for direct interrupt handling
*
* FIXME: This is used only client-internal and could thus be protected.
* Register irq signal handler
*/
virtual Irq_signal signal() = 0;
virtual void sigh(Genode::Signal_context_capability sigh) = 0;
/*************
** Session **
@ -82,9 +68,9 @@ struct Genode::Irq_session : Session
** RPC declaration **
*********************/
GENODE_RPC(Rpc_wait_for_irq, void, wait_for_irq);
GENODE_RPC(Rpc_signal, Irq_signal, signal);
GENODE_RPC_INTERFACE(Rpc_wait_for_irq, Rpc_signal);
GENODE_RPC(Rpc_ack_irq, void, ack_irq);
GENODE_RPC(Rpc_sigh, void, sigh, Genode::Signal_context_capability);
GENODE_RPC_INTERFACE(Rpc_ack_irq, Rpc_sigh);
};
#endif /* _INCLUDE__IRQ_SESSION__IRQ_SESSION_H_ */

View File

@ -11,9 +11,18 @@
* under the terms of the GNU General Public License version 2.
*/
#include <irq_session/client.h>
#include <irq_session/connection.h>
void Genode::Irq_session_client::wait_for_irq()
void Genode::Irq_session_client::ack_irq()
{
call<Rpc_wait_for_irq>();
call<Rpc_ack_irq>();
}
void Genode::Irq_connection::wait_for_irq()
{
ack_irq();
Signal s = _sig_rec.wait_for_signal();
if (s.num() != 1)
PWRN("unexpected number of IRqs received %u", s.num());
}

View File

@ -9,36 +9,34 @@
#define _CORE__INCLUDE__IRQ_PROXY_H_
#include <base/env.h>
#include <util.h>
#include <base/thread.h>
namespace Genode {
class Irq_blocker;
class Irq_sigh;
template <typename THREAD> class Irq_proxy;
class Irq_thread_dummy;
class Irq_proxy_single;
}
class Genode::Irq_blocker : public Genode::List<Genode::Irq_blocker>::Element
class Genode::Irq_sigh : public Genode::Signal_context_capability,
public Genode::List<Genode::Irq_sigh>::Element
{
private:
Lock _wait_lock;
public:
Irq_blocker() : _wait_lock(Lock::LOCKED) { }
inline Irq_sigh * operator= (const Signal_context_capability &cap)
{
Signal_context_capability::operator=(cap);
return this;
}
void block() { _wait_lock.lock(); }
void unblock() { _wait_lock.unlock(); }
Irq_sigh() { }
void notify() { Genode::Signal_transmitter(*this).submit(1); }
};
/*
* Proxy thread that associates to the interrupt and unblocks waiting irqctrl
* threads. Maybe, we should utilize our signals for interrupt delivery...
* threads.
*
* XXX resources are not accounted as the interrupt is shared
*/
@ -56,8 +54,8 @@ class Genode::Irq_proxy : public THREAD,
Lock _mutex; /* protects this object */
int _num_sharers; /* number of clients sharing this IRQ */
Semaphore _sleep; /* wake me up if aspired blockers return */
List<Irq_blocker> _blocker_list;
int _num_blockers; /* number of currently blocked clients */
List<Irq_sigh> _sigh_list;
int _num_acknowledgers; /* number of currently blocked clients */
bool _woken_up; /* client decided to wake me up -
this prevents multiple wakeups
to happen during initialization */
@ -102,20 +100,8 @@ class Genode::Irq_proxy : public THREAD,
while (1) {
_wait_for_irq();
{
Lock::Guard lock_guard(_mutex);
/* inform blocked clients */
Irq_blocker *b;
while ((b = _blocker_list.first())) {
_blocker_list.remove(b);
b->unblock();
}
/* reset blocker state */
_num_blockers = 0;
_woken_up = false;
}
/* notify all */
notify_about_irq(1);
/*
* We must wait for all clients to ack their interrupt,
@ -146,7 +132,8 @@ class Genode::Irq_proxy : public THREAD,
:
THREAD(_construct_name(irq_number)),
_startup_lock(Lock::LOCKED), _irq_number(irq_number),
_mutex(Lock::UNLOCKED), _num_sharers(0), _num_blockers(0), _woken_up(false)
_mutex(Lock::UNLOCKED), _num_sharers(0), _num_acknowledgers(0), _woken_up(false)
{ }
/**
@ -163,43 +150,68 @@ class Genode::Irq_proxy : public THREAD,
}
/**
* Block until interrupt occured
* Acknowledgements of clients
*/
virtual void wait_for_irq()
virtual bool ack_irq()
{
Irq_blocker blocker;
{
Lock::Guard lock_guard(_mutex);
Lock::Guard lock_guard(_mutex);
_blocker_list.insert(&blocker);
_num_blockers++;
_num_acknowledgers++;
/*
* The proxy thread is woken up if no client woke it up before
* and this client is the last aspired blocker.
*/
if (!_woken_up && _num_blockers == _num_sharers) {
_sleep.up();
_woken_up = true;
}
/*
* The proxy thread has to be woken up if no client woke it up
* before and this client is the last aspired acknowledger.
*/
if (!_woken_up && _num_acknowledgers == _num_sharers) {
_sleep.up();
_woken_up = true;
}
blocker.block();
return _woken_up;
}
/**
* Notify all clients about irq
*/
void notify_about_irq(unsigned)
{
Lock::Guard lock_guard(_mutex);
/* reset acknowledger state */
_num_acknowledgers = 0;
_woken_up = false;
/* inform blocked clients */
for (Irq_sigh * s = _sigh_list.first(); s ; s = s->next())
s->notify();
}
long irq_number() const { return _irq_number; }
virtual bool add_sharer()
virtual bool add_sharer(Irq_sigh *s)
{
Lock::Guard lock_guard(_mutex);
++_num_sharers;
_sigh_list.insert(s);
return true;
}
virtual void remove_sharer()
virtual void remove_sharer(Irq_sigh *s)
{
Lock::Guard lock_guard(_mutex);
_sigh_list.remove(s);
--_num_sharers;
if (_woken_up)
return;
if (_num_acknowledgers == _num_sharers) {
_sleep.up();
_woken_up = true;
}
}
template <typename PROXY>
@ -225,51 +237,4 @@ class Genode::Irq_proxy : public THREAD,
}
};
/**
* Dummy thread
*/
class Genode::Irq_thread_dummy
{
public:
Irq_thread_dummy(char const *name) { }
void start() { }
};
/**
* Non-threaded proxy that disables shared interrupts
*/
class Genode::Irq_proxy_single : public Genode::Irq_proxy<Genode::Irq_thread_dummy>
{
protected:
void _start()
{
_associate();
}
public:
Irq_proxy_single(long irq_number) : Irq_proxy(irq_number) { }
bool add_sharer()
{
Lock::Guard lock_guard(_mutex);
if (_num_sharers)
return false;
_num_sharers = 1;
return true;
}
void wait_for_irq()
{
_wait_for_irq();
_ack_irq();
}
};
#endif /* _CORE__INCLUDE__IRQ_PROXY_H_ */

View File

@ -1,13 +1,12 @@
/*
* \brief IRQ root interface
* \author Christian Helmuth
* \author Alexander Boettcher
* \date 2007-09-13
*
* FIXME locking
*/
/*
* Copyright (C) 2007-2013 Genode Labs GmbH
* Copyright (C) 2007-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.
@ -16,98 +15,37 @@
#ifndef _CORE__INCLUDE__IRQ_ROOT_H_
#define _CORE__INCLUDE__IRQ_ROOT_H_
/* Genode includes */
#include <util/arg_string.h>
#include <base/allocator.h>
#include <root/root.h>
#include <base/rpc_server.h>
/* core includes */
#include <root/component.h>
#include <irq_session_component.h>
namespace Genode {
namespace Genode { class Irq_root; }
class Irq_root : public Rpc_object<Typed_root<Irq_session> >
{
class Genode::Irq_root : public Root_component<Irq_session_component>
{
private:
private:
Cap_session *_cap_session;
Range_allocator *_irq_alloc; /* platform irq allocator */
Allocator *_md_alloc; /* meta-data allocator */
List<Irq_session_component> _sessions; /* started irq sessions */
Range_allocator *_irq_alloc; /* platform irq allocator */
public:
protected:
/**
* Constructor
*
* \param cap_session capability allocator
* \param irq_alloc IRQ range that can be assigned to clients
* \param md_alloc meta-data allocator to be used by root component
*/
Irq_root(Cap_session *cap_session,
Range_allocator *irq_alloc,
Allocator *md_alloc)
: _cap_session(cap_session), _irq_alloc(irq_alloc), _md_alloc(md_alloc) { }
Irq_session_component *_create_session(const char *args) {
return new (md_alloc()) Irq_session_component(_irq_alloc, args); }
public:
/********************
** Root interface **
********************/
Session_capability session(Session_args const &args, Affinity const &affinity)
{
if (!args.is_valid_string()) throw Invalid_args();
/*
* We need to decrease 'ram_quota' by
* the size of the session object.
*/
size_t ram_quota = Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0);
long remaining_ram_quota = ram_quota - sizeof(Irq_session_component) -
_md_alloc->overhead(sizeof(Irq_session_component));
if (remaining_ram_quota < 0) {
PERR("Insufficient ram quota, provided=%zu, required=%zu",
ram_quota, sizeof(Irq_session_component) +
_md_alloc->overhead(sizeof(Irq_session_component)));
return Session_capability();
}
Irq_session_component *s;
try {
s = new (_md_alloc) Irq_session_component(_cap_session, _irq_alloc, args.string());
} catch (Allocator::Out_of_memory) { return Session_capability(); }
if (!s->cap().valid())
return Session_capability();
_sessions.insert(s);
return s->cap();
}
void upgrade(Session_capability, Upgrade_args const &)
{
/* there is no need to upgrade an IRQ session */
}
void close(Session_capability session)
{
Irq_session_component *s = _sessions.first();
for (; s; s = s->next()) {
if (s->cap().local_name() == session.local_name())
break;
}
if (!s) return;
_sessions.remove(s);
/* XXX Currently we support only one client... */
destroy(_md_alloc, s);
}
};
}
/**
* Constructor
*
* \param session_ep entry point for managing irq session objects
* \param irq_alloc IRQ range that can be assigned to clients
* \param md_alloc meta-data allocator to be used by root component
*/
Irq_root(Rpc_entrypoint *session_ep, Range_allocator *irq_alloc,
Allocator *md_alloc)
:
Root_component<Irq_session_component>(session_ep, md_alloc),
_irq_alloc(irq_alloc) { }
};
#endif /* _CORE__INCLUDE__IRQ_ROOT_H_ */

View File

@ -14,128 +14,51 @@
#ifndef _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_
#include <base/lock.h>
#include <base/rpc_server.h>
#include <base/rpc_client.h>
#include <util/list.h>
#include <irq_session/irq_session.h>
#include <irq_session/capability.h>
/* XXX Notes
*
* - each H/W IRQ is an irq thread
* - each irq thread has an Rpc_entrypoint
* -> irq thread is special Server_activation
* -> IRQ session is Rpc_object
*
* - session("IRQ", "irq_num=<num>") -> Native_capability(irq_thread, cap)
* - cap must be generated at CAP
* - cap must be managed by irq_thread-local Rpc_entrypoint
*
* - irq thread states
* 1. wait_for_client --[ client calls wait_for_irq ]--> 2.
* 2. wait_for_irq --[ kernel signals irq ]--> 3.
* 3. irq_occured --[ inform client about occurence ]--> 1.
*
* - irq thread roles
* - Irq_server (Ipc_server) for client
* - Fiasco_irq_client (Ipc_client) at kernel
*/
#include <irq_proxy.h>
namespace Genode {
class Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
private:
struct Irq_control
{
GENODE_RPC(Rpc_associate_to_irq, bool, associate_to_irq, unsigned);
GENODE_RPC_INTERFACE(Rpc_associate_to_irq);
};
struct Irq_control_client : Rpc_client<Irq_control>
{
Irq_control_client(Capability<Irq_control> cap)
: Rpc_client<Irq_control>(cap) { }
bool associate_to_irq(unsigned irq_number) {
return call<Rpc_associate_to_irq>(irq_number); }
};
struct Irq_control_component : Rpc_object<Irq_control,
Irq_control_component>
{
/**
* Associate to IRQ at Fiasco
*
* This is executed by the IRQ server activation itself.
*/
bool associate_to_irq(unsigned irq_number);
};
unsigned _irq_number;
Range_allocator *_irq_alloc;
enum { STACK_SIZE = 2048 };
Rpc_entrypoint _ep;
/*
* On Pistachio, an IRQ is unmasked right after attaching.
* Hence, the kernel may send an IRQ IPC when the IRQ hander is
* not explicitly waiting for an IRQ but when it is waiting for
* a client's 'wait_for_irq' RPC call. To avoid this conflict, we
* lazily associate to the IRQ when calling the 'wait_for_irq'
* function for the first time. We use the '_irq_attached' flag
* for detecting the first call. On other kernels, this variable
* may be unused.
*/
unsigned _irq_attached; /* true if IRQ is already attached */
/********************************************
** IRQ control server (internal use only) **
********************************************/
Irq_control_component _control_component; /* ctrl component */
Capability<Irq_control> _control_cap; /* capability for ctrl server */
Irq_control_client _control_client; /* ctrl client */
Capability<Irq_session> _irq_cap; /* capability for IRQ */
public:
/**
* Constructor
*
* \param cap_session capability session to use
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args);
/**
* Destructor
*/
~Irq_session_component();
/**
* Return capability to this session
*
* If an initialization error occurs, returned _cap is invalid.
*/
Capability<Irq_session> cap() const { return _irq_cap; }
/***************************
** Irq session interface **
***************************/
void wait_for_irq();
Irq_signal signal();
};
class Irq_proxy_component;
class Irq_session_component;
}
class Genode::Irq_session_component : public Rpc_object<Irq_session>,
public List<Irq_session_component>::Element
{
private:
unsigned _irq_number;
Range_allocator *_irq_alloc;
Irq_proxy_component *_proxy;
Irq_sigh _irq_sigh;
public:
/**
* Constructor
*
* \param irq_alloc platform-dependent IRQ allocator
* \param args session construction arguments
*/
Irq_session_component(Range_allocator *irq_alloc,
const char *args);
/**
* Destructor
*/
~Irq_session_component();
/***************************
** Irq session interface **
***************************/
void ack_irq();
void sigh(Signal_context_capability) override;
};
#endif /* _CORE__INCLUDE__IRQ_SESSION_COMPONENT_H_ */

View File

@ -220,8 +220,7 @@ int main()
static Log_root log_root (e, &sliced_heap);
static Io_mem_root io_mem_root (e, e, platform()->io_mem_alloc(),
platform()->ram_alloc(), &sliced_heap);
static Irq_root irq_root (core_env()->cap_session(),
platform()->irq_alloc(), &sliced_heap);
static Irq_root irq_root (e, platform()->irq_alloc(), &sliced_heap);
static Trace::Root trace_root (e, &sliced_heap, trace_sources, trace_policies);
/*