hw: handle interrupts via signals

fix #874
This commit is contained in:
Martin Stein 2013-10-30 13:56:57 +01:00 committed by Norman Feske
parent b88d7e3370
commit 47744e0019
25 changed files with 853 additions and 541 deletions

View File

@ -0,0 +1,62 @@
/*
* \brief Client-side IRQ session interface
* \author Martin Stein
* \date 2013-10-24
*/
/*
* Copyright (C) 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 _IRQ_SESSION__CLIENT_H_
#define _IRQ_SESSION__CLIENT_H_
/* Genode includes */
#include <irq_session/capability.h>
#include <base/rpc_client.h>
namespace Genode
{
/**
* Client-side IRQ session interface
*/
struct 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
*
* \param session pointer to the session backend
*/
explicit Irq_session_client(Irq_session_capability const & session)
:
Rpc_client<Irq_session>(session),
irq_signal(signal())
{ }
/*****************
** Irq_session **
*****************/
Irq_signal signal() { return call<Rpc_signal>(); }
void wait_for_irq()
{
while (Kernel::await_signal(irq_signal.receiver_id,
irq_signal.context_id))
{
PERR("failed to receive interrupt");
}
}
};
}
#endif /* _IRQ_SESSION__CLIENT_H_ */

View File

@ -0,0 +1,82 @@
/*
* \brief IRQ session interface
* \author Martin Stein
* \date 2013-10-24
*/
/*
* Copyright (C) 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 _IRQ_SESSION__IRQ_SESSION_H_
#define _IRQ_SESSION__IRQ_SESSION_H_
/* Genode includes */
#include <base/capability.h>
#include <session/session.h>
namespace Genode
{
/**
* Information that enables a user to await and ack an IRQ directly
*/
struct Irq_signal
{
unsigned receiver_id;
unsigned context_id;
};
/**
* IRQ session interface
*/
struct Irq_session : Session
{
/**
* Interrupt trigger
*/
enum Trigger { TRIGGER_UNCHANGED = 0, TRIGGER_LEVEL, TRIGGER_EDGE };
/**
* Interrupt trigger polarity
*/
enum Polarity { POLARITY_UNCHANGED = 0, POLARITY_HIGH, POLARITY_LOW };
/**
* Destructor
*/
virtual ~Irq_session() { }
/**
* Await the next occurence of the interrupt of this session
*/
virtual void wait_for_irq() = 0;
/**
* Get information for direct interrupt handling
*
* FIXME: This is used only client-internal and could thus be protected.
*/
virtual Irq_signal signal() = 0;
/*************
** Session **
*************/
static const char * service_name() { return "IRQ"; }
/*********************
** 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);
};
}
#endif /* _IRQ_SESSION__IRQ_SESSION_H_ */

View File

@ -64,11 +64,6 @@ namespace Kernel
NEW_PD = 13,
KILL_PD = 34,
/* interrupt handling */
ALLOCATE_IRQ = 14,
AWAIT_IRQ = 15,
FREE_IRQ = 16,
/* debugging */
PRINT_CHAR = 17,
@ -392,40 +387,6 @@ namespace Kernel
inline void print_char(char const c)
{ syscall(PRINT_CHAR, (Syscall_arg)c); }
/**
* Allocate an IRQ to the caller if the IRQ is not allocated already
*
* \param id ID of the targeted IRQ
*
* \return wether the IRQ has been allocated to this thread or not
*
* Restricted to core threads.
*/
inline bool allocate_irq(unsigned const id) {
return syscall(ALLOCATE_IRQ, (Syscall_arg)id); }
/**
* Free an IRQ from allocation if it is allocated by the caller
*
* \param id ID of the targeted IRQ
*
* \return wether the IRQ has been freed or not
*
* Restricted to core threads.
*/
inline bool free_irq(unsigned const id) {
return syscall(FREE_IRQ, (Syscall_arg)id); }
/**
* Block caller for the occurence of its IRQ
*
* Restricted to core threads. Blocks the caller forever
* if he has not allocated any IRQ.
*/
inline void await_irq() { syscall(AWAIT_IRQ); }
/**
* Copy the current state of a thread to the callers UTCB
@ -492,25 +453,29 @@ namespace Kernel
/**
* Wait for the occurence of any context of a receiver
* Await any context of a receiver and optionally ack a context before
*
* \param receiver kernel name of the targeted signal receiver
* \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.
* If multiple threads listen at the same receiver, and/or
* multiple contexts of the receiver trigger simultanously, there is no
* assertion about wich thread receives, and from wich context. A context
* that delivered once doesn't deliver again unless its last delivery has
* been acknowledged via 'ack_signal'.
* through this function until it gets delivered through this function or
* context respectively receiver get destructed. If multiple threads
* listen at the same receiver, and/or multiple contexts of the receiver
* trigger simultanously, there is no assertion about wich thread
* receives, and from wich context. A context that delivered once doesn't
* deliver again unless its last delivery has been acknowledged via
* ack_signal.
*/
inline int await_signal(unsigned const receiver)
inline int await_signal(unsigned const receiver_id,
unsigned const context_id)
{
return syscall(AWAIT_SIGNAL, receiver);
return syscall(AWAIT_SIGNAL, receiver_id, context_id);
}

View File

@ -177,7 +177,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())) {
if (Kernel::await_signal(_cap.dst(), 0)) {
PERR("failed to receive signal");
return Signal(Signal::Data());
}

View File

@ -16,10 +16,43 @@
#include <platform.h>
#include <pic.h>
#include <timer.h>
#include <kernel/irq.h>
using namespace Genode;
namespace Kernel { void init_platform(); }
/**
* Interrupts that core shall provide to users
*/
static unsigned irq_ids[] =
{
Board::PWM_IRQ_0,
Board::USB_HOST20_IRQ,
Board::USB_DRD30_IRQ,
Board::SATA_IRQ,
Board::I2C_HDMI_IRQ,
Board::SDMMC0_IRQ
};
enum { IRQ_IDS_SIZE = sizeof(irq_ids)/sizeof(irq_ids[0]) };
void Kernel::init_platform()
{
/* make user IRQs become known by cores IRQ session backend and kernel */
static uint8_t _irqs[IRQ_IDS_SIZE][sizeof(Irq)];
for (unsigned i = 0; i < IRQ_IDS_SIZE; i++) {
new (_irqs[i]) Irq(irq_ids[i]);
}
}
unsigned * Platform::_irq(unsigned const i)
{
return i < IRQ_IDS_SIZE ? &irq_ids[i] : 0;
}
Native_region * Platform::_ram_regions(unsigned const i)
{
@ -31,26 +64,6 @@ Native_region * Platform::_ram_regions(unsigned const i)
}
Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Kernel::Pic::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ Kernel::Timer::IRQ, 1 },
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_mmio_regions(unsigned const i)
{
static Native_region _regions[] =

View File

@ -15,9 +15,38 @@
#include <platform.h>
#include <board.h>
#include <pic.h>
#include <kernel/irq.h>
using namespace Genode;
namespace Kernel { void init_platform(); }
/**
* Interrupts that core shall provide to users
*/
static unsigned irq_ids[] =
{
Board::EPIT_2_IRQ
};
enum { IRQ_IDS_SIZE = sizeof(irq_ids)/sizeof(irq_ids[0]) };
void Kernel::init_platform()
{
/* make user IRQs become known by cores IRQ session backend and kernel */
static uint8_t _irqs[IRQ_IDS_SIZE][sizeof(Irq)];
for (unsigned i = 0; i < IRQ_IDS_SIZE; i++) {
new (_irqs[i]) Irq(irq_ids[i]);
}
}
unsigned * Platform::_irq(unsigned const i)
{
return i < IRQ_IDS_SIZE ? &irq_ids[i] : 0;
}
Native_region * Platform::_ram_regions(unsigned const i)
{
@ -29,30 +58,6 @@ Native_region * Platform::_ram_regions(unsigned const i)
}
Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Imx31::Pic::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* core timer */
{ Board::EPIT_1_IRQ, 1 },
/* core UART */
{ Board::UART_1_IRQ, 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_mmio_regions(unsigned const i)
{
static Native_region _regions[] =

View File

@ -15,9 +15,54 @@
#include <platform.h>
#include <board.h>
#include <pic.h>
#include <kernel/irq.h>
using namespace Genode;
namespace Kernel { void init_platform(); }
/**
* Interrupts that core shall provide to users
*/
static unsigned irq_ids[] =
{
Board::EPIT_2_IRQ,
Board::GPIO1_IRQL,
Board::GPIO1_IRQH,
Board::GPIO2_IRQL,
Board::GPIO2_IRQH,
Board::GPIO3_IRQL,
Board::GPIO3_IRQH,
Board::GPIO4_IRQL,
Board::GPIO4_IRQH,
Board::GPIO5_IRQL,
Board::GPIO5_IRQH,
Board::GPIO6_IRQL,
Board::GPIO6_IRQH,
Board::GPIO7_IRQL,
Board::GPIO7_IRQH,
Board::I2C_2_IRQ,
Board::I2C_3_IRQ
};
enum { IRQ_IDS_SIZE = sizeof(irq_ids)/sizeof(irq_ids[0]) };
void Kernel::init_platform()
{
/* make user IRQs become known by cores IRQ session backend and kernel */
static uint8_t _irqs[IRQ_IDS_SIZE][sizeof(Irq)];
for (unsigned i = 0; i < IRQ_IDS_SIZE; i++) {
new (_irqs[i]) Irq(irq_ids[i]);
}
}
unsigned * Platform::_irq(unsigned const i)
{
return i < IRQ_IDS_SIZE ? &irq_ids[i] : 0;
}
Native_region * Platform::_ram_regions(unsigned const i)
{
@ -29,30 +74,6 @@ Native_region * Platform::_ram_regions(unsigned const i)
}
Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Imx53::Pic::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* core timer */
{ Board::EPIT_1_IRQ, 1 },
/* core UART */
{ Board::UART_1_IRQ, 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_mmio_regions(unsigned const i)
{
static Native_region _regions[] =

View File

@ -0,0 +1,74 @@
/*
* \brief Backend for IRQ sessions served by core
* \author Martin Stein
* \date 2013-10-29
*/
/*
* Copyright (C) 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 _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;
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();
};
}
#endif /* _INCLUDE__IRQ_SESSION_COMPONENT_H_ */

View File

@ -17,6 +17,7 @@
/* Genode includes */
#include <base/sync_allocator.h>
#include <base/allocator_avl.h>
#include <irq_session/irq_session.h>
#include <kernel/log.h>
#include <kernel/syscalls.h>
@ -52,7 +53,6 @@ namespace Genode {
*/
static Native_region * _ram_regions(unsigned i);
static Native_region * _mmio_regions(unsigned i);
static Native_region * _irq_regions(unsigned i);
/**
* Get one of the consecutively numbered core regions
@ -66,7 +66,16 @@ namespace Genode {
*/
static Native_region * _core_only_ram_regions(unsigned i);
static Native_region * _core_only_mmio_regions(unsigned i);
static Native_region * _core_only_irq_regions(unsigned i);
/**
* Get one of the consecutively numbered user interrupts
*
* \param i index of interrupt
*
* \return >0 pointer to the name of the requested interrupt
* 0 no interrupt for that index
*/
static unsigned * _irq(unsigned const i);
public:

View File

@ -1,5 +1,5 @@
/*
* \brief Implementation of IRQ session component
* \brief Backend for IRQ sessions served by core
* \author Martin Stein
* \date 2012-02-12
*/
@ -15,56 +15,54 @@
#include <kernel/syscalls.h>
/* core includes */
#include <kernel/irq.h>
#include <irq_root.h>
#include <core_env.h>
using namespace Genode;
bool
Irq_session_component::Irq_control_component::associate_to_irq(unsigned irq)
{ return Kernel::allocate_irq(irq); }
void Irq_session_component::wait_for_irq() { Kernel::await_irq(); }
Irq_session_component::~Irq_session_component()
/**
* 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()
{
/* free IRQ for other threads */
if (Kernel::free_irq(_irq_number))
PERR("Could not free IRQ %u", _irq_number);
enum { STACK_SIZE = 2048 };
static Rpc_entrypoint
_ep(core_env()->cap_session(), STACK_SIZE, "irq_session_ep");
return &_ep;
}
void Irq_session_component::wait_for_irq() { PERR("not implemented"); }
Irq_session_component::Irq_session_component(Cap_session * cap_session,
Range_allocator * irq_alloc,
const char * args)
Irq_signal Irq_session_component::signal() { return _signal; }
Irq_session_component::~Irq_session_component() { PERR("not implemented"); }
Irq_session_component::Irq_session_component(Cap_session * const cap_session,
Range_allocator * const irq_alloc,
const char * const 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)
{
/* check arguments */
bool shared = Arg_string::find_arg(args, "irq_shared").bool_value(false);
if (shared) {
PERR("IRQ sharing not supported");
PERR("shared interrupts not supported");
throw Root::Invalid_args();
}
/* allocate IRQ */
/* allocate interrupt */
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (irq_number < 0 || !irq_alloc ||
irq_alloc->alloc_addr(1, irq_number).is_error())
{
PERR("Unavailable IRQ %lu requested", irq_number);
bool error = irq_number < 0 || !_irq_alloc;
error |= _irq_alloc->alloc_addr(1, irq_number).is_error();
if (error) {
PERR("unavailable interrupt requested");
throw Root::Invalid_args();
}
_irq_number = irq_number;
/* configure control client */
if (!_control_client.associate_to_irq(irq_number)) {
PERR("IRQ association failed");
throw Root::Invalid_args();
}
/* create IRQ capability */
_irq_cap = Irq_session_capability(_ep.manage(this));
/* make interrupt accessible */
_signal = Irq::signal(irq_number);
_cap = Irq_session_capability(irq_session_ep()->manage(this));
}

View File

@ -25,9 +25,11 @@
/* core includes */
#include <kernel/pd.h>
#include <kernel/vm.h>
#include <kernel/irq.h>
#include <platform_pd.h>
#include <trustzone.h>
#include <timer.h>
#include <pic.h>
/* base-hw includes */
#include <singleton.h>
@ -42,9 +44,16 @@ extern "C" void CORE_MAIN();
namespace Kernel
{
/**
* Return interrupt-controller singleton
*/
Pic * pic() { return unsynchronized_singleton<Pic>(); }
/* import Genode types */
typedef Genode::umword_t umword_t;
typedef Genode::Core_tlb Core_tlb;
void init_platform();
}
namespace Kernel
@ -142,10 +151,10 @@ namespace Kernel
void handle_interrupt()
{
/* determine handling for specific interrupt */
unsigned irq;
if (pic()->take_request(irq))
unsigned irq_id;
if (pic()->take_request(irq_id))
{
switch (irq) {
switch (irq_id) {
case Timer::IRQ: {
@ -156,9 +165,7 @@ namespace Kernel
default: {
Irq_receiver * const o = Irq_receiver::receiver(irq);
assert(o);
o->receive_irq(irq);
Irq::occurred(irq_id);
break; }
}
}
@ -180,7 +187,7 @@ extern "C" void kernel()
{
static bool initial_call = true;
/* an exception occured */
/* an exception occurred */
if (!initial_call)
{
/* handle exception that interrupted the last user */
@ -189,8 +196,6 @@ extern "C" void kernel()
/* kernel initialization */
} else {
Genode::printf("Kernel started!\n");
/* enable kernel timer */
pic()->unmask(Timer::IRQ);
@ -221,8 +226,8 @@ extern "C" void kernel()
static Thread t((Platform_thread *)0);
t.init(ip, sp, 0, core_id(), &utcb, &utcb, 1, 1);
}
/* kernel initialization finished */
init_platform();
reset_lap_time();
initial_call = false;
}

View File

@ -0,0 +1,24 @@
/*
* \brief Kernel back-end and core front-end for user interrupts
* \author Martin Stein
* \date 2013-10-28
*/
/*
* Copyright (C) 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.
*/
/* core includes */
#include <kernel/irq.h>
#include <pic.h>
using namespace Kernel;
namespace Kernel { Pic * pic(); }
void Irq::_disable() const { pic()->mask(_id()); }
void Irq::_enable() const { pic()->unmask(_id()); }

View File

@ -0,0 +1,182 @@
/*
* \brief Kernel back-end and core front-end for user interrupts
* \author Martin Stein
* \date 2013-10-28
*/
/*
* Copyright (C) 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 _KERNEL__IRQ_H_
#define _KERNEL__IRQ_H_
/* Genode includes */
#include <base/native_types.h>
#include <irq_session/irq_session.h>
/* core includes */
#include <kernel/signal_receiver.h>
namespace Kernel
{
/**
* Kernel back-end of a user interrupt
*/
class Irq;
}
namespace Genode
{
/**
* Core front-end of a user interrupt
*/
class Irq;
}
class Kernel::Irq
:
public Object_pool<Irq>::Item,
public Signal_receiver,
public Signal_context
{
friend class Genode::Irq;
private:
typedef Object_pool<Irq> Pool;
/**
* Get map that provides all user interrupts by their kernel names
*/
static Pool * _pool()
{
static Pool p;
return &p;
}
/**
* Prevent interrupt from occurring
*/
void _disable() const;
/**
* Allow interrupt to occur
*/
void _enable() const;
/**
* Get kernel name of the interrupt
*/
unsigned _id() const { return Pool::Item::id(); };
/**
* 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(); }
/**
* Handle occurence of the interrupt
*/
void _occurred()
{
Signal_context::submit(1);
_disable();
}
/**
* Get information that enables a user to handle an interrupt
*
* \param irq_id kernel name of targeted interrupt
*/
static Genode::Irq_signal _genode_signal(unsigned const irq_id)
{
typedef Genode::Irq_signal Irq_signal;
static Irq_signal const invalid = { 0, 0 };
Irq * const irq = _pool()->object(irq_id);
if (irq) {
Irq_signal s = { irq->_receiver_id(), irq->_context_id() };
return s;
}
return invalid;
}
/**
* Destructor
*
* By now, there is no use case to destruct user interrupts
*/
~Irq() { PERR("method not implemented"); }
/********************
** Signal_context **
********************/
void _signal_context_acknowledged() { _enable(); }
public:
/**
* Placement-new operator
*
* \param p destination of new object
*
* \return destination of new object
*/
void * operator new (size_t, void * p) { return p; }
/**
* Constructor
*
* \param irq_id kernel name of the interrupt
*/
Irq(unsigned const irq_id)
:
Pool::Item(irq_id),
Signal_context(this)
{
_pool()->insert(this);
_disable();
}
/**
* Handle occurence of an interrupt
*
* \param irq_id kernel name of targeted interrupt
*/
static void occurred(unsigned const irq_id)
{
Irq * const irq = _pool()->object(irq_id);
if (!irq) {
PERR("unknown interrupt occurred");
return;
}
irq->_occurred();
}
};
class Genode::Irq
{
public:
/**
* Get information that enables a user to handle an interrupt
*
* \param irq_id kernel name of targeted interrupt
*/
static Irq_signal signal(unsigned const irq_id)
{
return Kernel::Irq::_genode_signal(irq_id);
}
};
#endif /* _KERNEL__IRQ_H_ */

View File

@ -1,167 +0,0 @@
/*
* \brief Exclusive ownership and handling of interrupts
* \author Martin Stein
* \date 2012-11-30
*/
/*
* 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 _KERNEL__IRQ_RECEIVER_H_
#define _KERNEL__IRQ_RECEIVER_H_
/* core includes */
#include <pic.h>
#include <assert.h>
#include <kernel/object.h>
namespace Kernel
{
/**
* Exclusive ownership and handling of one interrupt at a time
*/
class Irq_receiver;
/**
* Return interrupt-controller singleton
*/
static Pic * pic() { return unsynchronized_singleton<Pic>(); }
}
class Kernel::Irq_receiver : public Object_pool<Irq_receiver>::Item
{
private:
typedef Object_pool<Irq_receiver> Pool;
/**
* Return map that maps assigned interrupts to their receivers
*/
static Pool * _pool() { static Pool _pool; return &_pool; }
/**
* Translate receiver ID 'id' to interrupt ID
*/
static unsigned _id_to_irq(unsigned id) { return id - 1; }
/**
* Translate interrupt ID 'id' to receiver ID
*/
static unsigned _irq_to_id(unsigned irq) { return irq + 1; }
/**
* Free interrupt of this receiver without sanity checks
*/
void _free_irq()
{
_pool()->remove(this);
_id = 0;
}
/**
* Stop receiver from waiting for its interrupt without sanity checks
*/
void _cancel_waiting() { pic()->mask(_id_to_irq(_id)); }
/**
* Gets called as soon as the receivers interrupt occurs
*/
virtual void _received_irq() = 0;
/**
* Gets called when receiver starts waiting for its interrupt
*/
virtual void _awaits_irq() = 0;
public:
/**
* Constructor
*/
Irq_receiver() : Pool::Item(0) { }
/**
* Destructor
*/
~Irq_receiver()
{
if (_id) {
_cancel_waiting();
_free_irq();
}
}
/**
* Assign interrupt 'irq' to the receiver
*
* \return wether the assignment succeeded
*/
bool allocate_irq(unsigned const irq)
{
/* check if an allocation is needed and possible */
unsigned const id = _irq_to_id(irq);
if (_id) { return _id == id; }
if (_pool()->object(id)) { return 0; }
/* allocate and mask the interrupt */
pic()->mask(irq);
_id = id;
_pool()->insert(this);
return 1;
}
/**
* Unassign interrupt 'irq' if it is assigned to the receiver
*
* \return wether the unassignment succeeded
*/
bool free_irq(unsigned const irq)
{
if (_id != _irq_to_id(irq)) { return 0; }
_free_irq();
return 1;
}
/**
* Unmask and await interrupt that is assigned to the receiver
*/
void await_irq()
{
if (!_id) {
PERR("waiting for imaginary interrupt");
return;
}
unsigned const irq = _id_to_irq(_id);
pic()->unmask(irq);
_awaits_irq();
}
/**
* Stop waiting for the interrupt of the receiver
*/
void cancel_waiting() { if (_id) { _cancel_waiting(); } }
/**
* Denote that the receivers interrupt 'irq' occured and mask it
*/
void receive_irq(unsigned const irq)
{
assert(_id == _irq_to_id(irq));
pic()->mask(irq);
_received_irq();
}
/**
* Get receiver of IRQ 'irq' or 0 if the IRQ isn't assigned
*/
static Irq_receiver * receiver(unsigned irq)
{
return _pool()->object(_irq_to_id(irq));
}
};
#endif /* _KERNEL__IRQ_RECEIVER_H_ */

View File

@ -44,3 +44,11 @@ void Signal_context::_deliverable()
Signal_context::~Signal_context() { _receiver->_context_killed(this); }
Signal_context::Signal_context(Signal_receiver * const r)
:
_deliver_fe(this), _contexts_fe(this), _receiver(r),
_imprint(Object::id()), _submits(0), _ack(1), _kill(0), _killer(0)
{
r->add_context(this);
}

View File

@ -232,12 +232,7 @@ class Kernel::Signal_context
void _killer_cancelled() { _killer = 0; }
/**
* Destructor
*/
~Signal_context();
/**
* Constructor
* Constructor that is used by signal receivers
*
* \param r receiver that the context is assigned to
* \param imprint userland identification of the context
@ -248,6 +243,25 @@ class Kernel::Signal_context
_imprint(imprint), _submits(0), _ack(1), _kill(0), _killer(0)
{ }
/**
* Hook to install in-kernel handler for acks at specific signal types
*/
virtual void _signal_context_acknowledged() { };
protected:
/**
* Constructor that is used by
*
* \param r receiver that the context is assigned to
*/
Signal_context(Signal_receiver * const r);
/**
* Destructor
*/
~Signal_context();
public:
/**
@ -271,6 +285,7 @@ class Kernel::Signal_context
*/
void ack()
{
_signal_context_acknowledged();
if (_ack) { return; }
if (!_kill) {
_ack = 1;
@ -441,6 +456,9 @@ class Kernel::Signal_receiver
/**
* Create a context that is assigned to the receiver
*
* \param p memory destination
* \param imprint userland identification of context
*
* \retval 0 succeeded
* \retval -1 failed
*/
@ -453,6 +471,19 @@ class Kernel::Signal_receiver
return 0;
}
/**
* Assign context 'c' to the receiver
*
* \retval 0 succeeded
* \retval -1 failed
*/
int add_context(Signal_context * const c)
{
if (_kill) { return -1; }
_contexts.enqueue(&c->_contexts_fe);
return 0;
}
/**
* Return wether any of the contexts of this receiver is deliverable
*/

View File

@ -161,20 +161,6 @@ void Thread::_await_ipc_failed()
}
void Thread::_received_irq()
{
assert(_state == AWAITS_IRQ);
_schedule();
}
void Thread::_awaits_irq()
{
cpu_scheduler()->remove(this);
_state = AWAITS_IRQ;
}
int Thread::_resume()
{
switch (_state) {
@ -192,9 +178,6 @@ int Thread::_resume()
case AWAITS_IPC:
Ipc_node::cancel_waiting();
return 0;
case AWAITS_IRQ:
Irq_receiver::cancel_waiting();
return 0;
case AWAITS_SIGNAL:
Signal_handler::cancel_waiting();
return 0;
@ -688,38 +671,6 @@ void Thread::_syscall_update_region()
}
/**
* Do specific syscall for this thread, for details see 'syscall.h'
*/
void Thread::_syscall_allocate_irq()
{
assert(_core());
unsigned irq = user_arg_1();
user_arg_0(allocate_irq(irq));
}
/**
* Do specific syscall for this thread, for details see 'syscall.h'
*/
void Thread::_syscall_free_irq()
{
assert(_core());
unsigned irq = user_arg_1();
user_arg_0(free_irq(irq));
}
/**
* Do specific syscall for this thread, for details see 'syscall.h'
*/
void Thread::_syscall_await_irq()
{
assert(_core());
await_irq();
}
/**
* Do specific syscall for this thread, for details see 'syscall.h'
*/
@ -767,7 +718,7 @@ void Thread::_syscall_new_signal_receiver()
return;
}
/* create receiver */
void * p = (void *)user_arg_1();
void * const p = (void *)user_arg_1();
Signal_receiver * const r = new (p) Signal_receiver();
user_arg_0(r->id());
}
@ -785,7 +736,7 @@ void Thread::_syscall_new_signal_context()
return;
}
/* lookup receiver */
unsigned id = user_arg_2();
unsigned const id = user_arg_2();
Signal_receiver * const r = Signal_receiver::pool()->object(id);
if (!r) {
PERR("unknown signal receiver");
@ -793,8 +744,8 @@ void Thread::_syscall_new_signal_context()
return;
}
/* create and assign context*/
void * p = (void *)user_arg_1();
unsigned imprint = user_arg_3();
void * const p = (void *)user_arg_1();
unsigned const imprint = user_arg_3();
if (r->new_context(p, imprint)) {
PERR("failed to create signal context");
user_arg_0(0);
@ -811,9 +762,16 @@ void Thread::_syscall_new_signal_context()
*/
void Thread::_syscall_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 { PERR("failed to acknowledge signal context"); }
}
/* lookup receiver */
unsigned id = user_arg_1();
Signal_receiver * const r = Signal_receiver::pool()->object(id);
unsigned const receiver_id = user_arg_1();
Signal_receiver * const r = Signal_receiver::pool()->object(receiver_id);
if (!r) {
PERR("unknown signal receiver");
user_arg_0(-1);
@ -835,7 +793,7 @@ void Thread::_syscall_await_signal()
void Thread::_syscall_signal_pending()
{
/* lookup signal receiver */
unsigned id = user_arg_1();
unsigned const id = user_arg_1();
Signal_receiver * const r = Signal_receiver::pool()->object(id);
if (!r) {
PERR("unknown signal receiver");
@ -876,7 +834,7 @@ void Thread::_syscall_submit_signal()
void Thread::_syscall_ack_signal()
{
/* lookup signal context */
unsigned id = user_arg_1();
unsigned const id = user_arg_1();
Signal_context * const c = Signal_context::pool()->object(id);
if (!c) {
PERR("unknown signal context");
@ -899,7 +857,7 @@ void Thread::_syscall_kill_signal_context()
return;
}
/* lookup signal context */
unsigned id = user_arg_1();
unsigned const id = user_arg_1();
Signal_context * const c = Signal_context::pool()->object(id);
if (!c) {
PERR("unknown signal context");
@ -928,7 +886,7 @@ void Thread::_syscall_kill_signal_receiver()
return;
}
/* lookup signal receiver */
unsigned id = user_arg_1();
unsigned const id = user_arg_1();
Signal_receiver * const r = Signal_receiver::pool()->object(id);
if (!r) {
PERR("unknown signal receiver");
@ -1028,9 +986,6 @@ void Thread::_syscall()
case UPDATE_PD: _syscall_update_pd(); return;
case UPDATE_REGION: _syscall_update_region(); return;
case NEW_PD: _syscall_new_pd(); return;
case ALLOCATE_IRQ: _syscall_allocate_irq(); return;
case AWAIT_IRQ: _syscall_await_irq(); return;
case FREE_IRQ: _syscall_free_irq(); return;
case PRINT_CHAR: _syscall_print_char(); return;
case NEW_SIGNAL_RECEIVER: _syscall_new_signal_receiver(); return;
case NEW_SIGNAL_CONTEXT: _syscall_new_signal_context(); return;

View File

@ -19,7 +19,6 @@
#include <kernel/scheduler.h>
#include <kernel/signal_receiver.h>
#include <kernel/ipc_node.h>
#include <kernel/irq_receiver.h>
#include <cpu.h>
namespace Genode
@ -56,7 +55,6 @@ class Kernel::Thread
public Object<Thread, MAX_THREADS, Thread_ids, thread_ids, thread_pool>,
public Execution_context,
public Ipc_node,
public Irq_receiver,
public Signal_context_killer,
public Signal_receiver_killer,
public Signal_handler
@ -73,7 +71,6 @@ class Kernel::Thread
AWAITS_RESUME = 4,
AWAITS_PAGER = 5,
AWAITS_PAGER_IPC = 6,
AWAITS_IRQ = 7,
AWAITS_SIGNAL = 8,
AWAITS_SIGNAL_CONTEXT_KILL = 9,
AWAITS_SIGNAL_RECEIVER_KILL = 10,
@ -160,9 +157,6 @@ class Kernel::Thread
void _syscall_set_pager();
void _syscall_update_pd();
void _syscall_update_region();
void _syscall_allocate_irq();
void _syscall_free_irq();
void _syscall_await_irq();
void _syscall_print_char();
void _syscall_read_thread_state();
void _syscall_write_thread_state();
@ -212,14 +206,6 @@ class Kernel::Thread
void _await_ipc_succeeded(size_t const s);
void _await_ipc_failed();
/***************
** Irq_owner **
***************/
void _received_irq();
void _awaits_irq();
public:
/**

View File

@ -16,9 +16,47 @@
#include <board.h>
#include <cpu.h>
#include <pic.h>
#include <kernel/irq.h>
using namespace Genode;
namespace Kernel { void init_platform(); }
/**
* Interrupts that core shall provide to users
*/
static unsigned irq_ids[] =
{
Board::GP_TIMER_3_IRQ,
Board::TL16C750_1_IRQ,
Board::TL16C750_2_IRQ,
Board::TL16C750_4_IRQ,
Board::GPIO1_IRQ,
Board::GPIO2_IRQ,
Board::GPIO3_IRQ,
Board::GPIO4_IRQ,
Board::GPIO5_IRQ,
Board::GPIO6_IRQ
};
enum { IRQ_IDS_SIZE = sizeof(irq_ids)/sizeof(irq_ids[0]) };
void Kernel::init_platform()
{
/* make user IRQs become known by cores IRQ session backend and kernel */
static uint8_t _irqs[IRQ_IDS_SIZE][sizeof(Irq)];
for (unsigned i = 0; i < IRQ_IDS_SIZE; i++) {
new (_irqs[i]) Irq(irq_ids[i]);
}
}
unsigned * Platform::_irq(unsigned const i)
{
return i < IRQ_IDS_SIZE ? &irq_ids[i] : 0;
}
Native_region * Platform::_ram_regions(unsigned const i)
{
@ -30,30 +68,6 @@ Native_region * Platform::_ram_regions(unsigned const i)
}
Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Kernel::Pic::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* core timer */
{ Genode::Cpu::PRIVATE_TIMER_IRQ, 1 },
/* core UART */
{ Board::TL16C750_3_IRQ, 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_mmio_regions(unsigned const i)
{
static Native_region _regions[] =

View File

@ -16,10 +16,46 @@
#include <board.h>
#include <cpu.h>
#include <pic.h>
#include <kernel/irq.h>
using namespace Genode;
namespace Kernel { void init_platform(); }
/**
* Interrupts that core shall provide to users
*/
static unsigned irq_ids[] =
{
Board::SP804_0_1_IRQ,
Board::KMI_0_IRQ,
Board::KMI_1_IRQ,
Board::ETHERNET_IRQ,
Board::PL011_1_IRQ,
Board::PL011_2_IRQ,
Board::PL011_3_IRQ,
Board::PL180_IRQ_0,
Board::PL180_IRQ_1
};
enum { IRQ_IDS_SIZE = sizeof(irq_ids)/sizeof(irq_ids[0]) };
void Kernel::init_platform()
{
/* make user IRQs become known by cores IRQ session backend and kernel */
static uint8_t _irqs[IRQ_IDS_SIZE][sizeof(Irq)];
for (unsigned i = 0; i < IRQ_IDS_SIZE; i++) {
new (_irqs[i]) Irq(irq_ids[i]);
}
}
unsigned * Platform::_irq(unsigned const i)
{
return i < IRQ_IDS_SIZE ? &irq_ids[i] : 0;
}
Native_region * Platform::_ram_regions(unsigned const i)
{
@ -32,30 +68,6 @@ Native_region * Platform::_ram_regions(unsigned const i)
}
Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Kernel::Pic::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* core timer */
{ Cortex_a9::Cpu::PRIVATE_TIMER_IRQ, 1 },
/* core UART */
{ Board::PL011_0_IRQ, 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_mmio_regions(unsigned const i)
{
static Native_region _regions[] =

View File

@ -122,7 +122,13 @@ Platform::Platform() :
enum { VERBOSE = 0 };
unsigned const psl2 = get_page_size_log2();
init_alloc(&_core_mem_alloc, _ram_regions, _core_only_ram_regions, psl2);
init_alloc(&_irq_alloc, _irq_regions, _core_only_irq_regions);
/* make interrupts available to the interrupt allocator */
for (unsigned i = 0; ; i++) {
unsigned * const irq = _irq(i);
if (!irq) { break; }
_irq_alloc.add_range(*irq, 1);
}
/*
* Use byte granuarity for MMIO regions because on some platforms, devices

View File

@ -14,9 +14,38 @@
/* core includes */
#include <platform.h>
#include <board.h>
#include <kernel/irq.h>
using namespace Genode;
namespace Kernel { void init_platform(); }
/**
* Interrupts that core shall provide to users
*/
static unsigned irq_ids[] =
{
Board::TIMER_IRQ
};
enum { IRQ_IDS_SIZE = sizeof(irq_ids)/sizeof(irq_ids[0]) };
void Kernel::init_platform()
{
/* make user IRQs become known by cores IRQ session backend and kernel */
static uint8_t _irqs[IRQ_IDS_SIZE][sizeof(Irq)];
for (unsigned i = 0; i < IRQ_IDS_SIZE; i++) {
new (_irqs[i]) Irq(irq_ids[i]);
}
}
unsigned * Platform::_irq(unsigned const i)
{
return i < IRQ_IDS_SIZE ? &irq_ids[i] : 0;
}
Native_region * Platform::_ram_regions(unsigned const i)
{
@ -28,31 +57,6 @@ Native_region * Platform::_ram_regions(unsigned const i)
}
Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, 64 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* system timer */
{ Board::SYSTEM_TIMER_IRQ, 1 },
/* UART */
{ Board::PL011_0_IRQ, 1 },
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_mmio_regions(unsigned const i)
{
static Native_region _regions[] =

View File

@ -50,6 +50,7 @@ SRC_CC += console.cc \
kernel/thread.cc \
kernel/vm.cc \
kernel/signal_receiver.cc \
kernel/irq.cc \
rm_session_support.cc \
kernel_support.cc \
trustzone.cc \

View File

@ -16,9 +16,46 @@
#include <board.h>
#include <cpu.h>
#include <pic.h>
#include <kernel/irq.h>
using namespace Genode;
namespace Kernel { void init_platform(); }
/**
* Interrupts that core shall provide to users
*/
static unsigned irq_ids[] =
{
Board::SP804_0_1_IRQ,
Board::KMI_0_IRQ,
Board::KMI_1_IRQ,
Board::LAN9118_IRQ,
Board::PL180_0_IRQ,
Board::PL180_1_IRQ,
Board::PL011_1_IRQ,
Board::PL011_2_IRQ,
Board::PL011_3_IRQ
};
enum { IRQ_IDS_SIZE = sizeof(irq_ids)/sizeof(irq_ids[0]) };
void Kernel::init_platform()
{
/* make user IRQs become known by cores IRQ session backend and kernel */
static uint8_t _irqs[IRQ_IDS_SIZE][sizeof(Irq)];
for (unsigned i = 0; i < IRQ_IDS_SIZE; i++) {
new (_irqs[i]) Irq(irq_ids[i]);
}
}
unsigned * Platform::_irq(unsigned const i)
{
return i < IRQ_IDS_SIZE ? &irq_ids[i] : 0;
}
Native_region * Platform::_ram_regions(unsigned const i)
{
@ -33,30 +70,6 @@ Native_region * Platform::_ram_regions(unsigned const i)
}
Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Kernel::Pic::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* Core timer */
{ Genode::Cpu::PRIVATE_TIMER_IRQ, 1 },
/* Core UART */
{ Board::PL011_0_IRQ, 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_mmio_regions(unsigned const i)
{
static Native_region _regions[] =

View File

@ -16,9 +16,45 @@
#include <platform.h>
#include <pic/vea9x4_trustzone.h>
#include <cpu/cortex_a9.h>
#include <kernel/irq.h>
using namespace Genode;
namespace Kernel { void init_platform(); }
/**
* Interrupts that core shall provide to users
*
* Interrupts that are used by the non-secure world are also
* not provided to the secure-world Genode to prevent contention.
*/
static unsigned irq_ids[] =
{
Board::PL180_0_IRQ,
Board::PL180_1_IRQ,
Board::PL011_1_IRQ,
Board::PL011_2_IRQ,
Board::PL011_3_IRQ
};
enum { IRQ_IDS_SIZE = sizeof(irq_ids)/sizeof(irq_ids[0]) };
void Kernel::init_platform()
{
/* make user IRQs become known by cores IRQ session backend and kernel */
static uint8_t _irqs[IRQ_IDS_SIZE][sizeof(Irq)];
for (unsigned i = 0; i < IRQ_IDS_SIZE; i++) {
new (_irqs[i]) Irq(irq_ids[i]);
}
}
unsigned * Platform::_irq(unsigned const i)
{
return i < IRQ_IDS_SIZE ? &irq_ids[i] : 0;
}
Native_region * Platform::_ram_regions(unsigned const i)
{
@ -30,33 +66,6 @@ Native_region * Platform::_ram_regions(unsigned const i)
}
Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, 34 },
{ 37, 3 },
{ 46, 1 },
{ 49, Vea9x4_trustzone::Pic::MAX_INTERRUPT_ID - 49 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_core_only_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
/* Core timer */
{ Cortex_a9::Cpu::PRIVATE_TIMER_IRQ, 1 },
/* Core UART */
{ Board::PL011_0_IRQ, 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_mmio_regions(unsigned const i)
{
static Native_region _regions[] =