From 47744e0019a32205b4e53cc53eb0d35258d387d3 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Wed, 30 Oct 2013 13:56:57 +0100 Subject: [PATCH] hw: handle interrupts via signals fix #874 --- base-hw/include/irq_session/client.h | 62 ++++++ base-hw/include/irq_session/irq_session.h | 82 ++++++++ base-hw/include/kernel/syscalls.h | 63 ++---- base-hw/src/base/signal/signal.cc | 2 +- base-hw/src/core/arndale/platform_support.cc | 55 ++++-- base-hw/src/core/imx31/platform_support.cc | 53 ++--- base-hw/src/core/imx53/platform_support.cc | 69 ++++--- .../src/core/include/irq_session_component.h | 74 +++++++ base-hw/src/core/include/platform.h | 13 +- base-hw/src/core/irq_session_component.cc | 68 ++++--- base-hw/src/core/kernel.cc | 25 ++- base-hw/src/core/kernel/irq.cc | 24 +++ base-hw/src/core/kernel/irq.h | 182 ++++++++++++++++++ base-hw/src/core/kernel/irq_receiver.h | 167 ---------------- base-hw/src/core/kernel/signal_receiver.cc | 8 + base-hw/src/core/kernel/signal_receiver.h | 43 ++++- base-hw/src/core/kernel/thread.cc | 79 ++------ base-hw/src/core/kernel/thread.h | 14 -- base-hw/src/core/panda/platform_support.cc | 62 +++--- base-hw/src/core/pbxa9/platform_support.cc | 62 +++--- base-hw/src/core/platform.cc | 8 +- base-hw/src/core/rpi/platform_support.cc | 54 +++--- base-hw/src/core/target.inc | 1 + .../vea9x4/no_trustzone/platform_support.cc | 61 +++--- .../core/vea9x4/trustzone/platform_support.cc | 63 +++--- 25 files changed, 853 insertions(+), 541 deletions(-) create mode 100644 base-hw/include/irq_session/client.h create mode 100644 base-hw/include/irq_session/irq_session.h create mode 100644 base-hw/src/core/include/irq_session_component.h create mode 100644 base-hw/src/core/kernel/irq.cc create mode 100644 base-hw/src/core/kernel/irq.h delete mode 100644 base-hw/src/core/kernel/irq_receiver.h diff --git a/base-hw/include/irq_session/client.h b/base-hw/include/irq_session/client.h new file mode 100644 index 000000000..8a417d989 --- /dev/null +++ b/base-hw/include/irq_session/client.h @@ -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 +#include + +namespace Genode +{ + /** + * Client-side IRQ session interface + */ + struct Irq_session_client : Rpc_client + { + /* + * 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(session), + irq_signal(signal()) + { } + + + /***************** + ** Irq_session ** + *****************/ + + Irq_signal signal() { return call(); } + + 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_ */ diff --git a/base-hw/include/irq_session/irq_session.h b/base-hw/include/irq_session/irq_session.h new file mode 100644 index 000000000..9060257e2 --- /dev/null +++ b/base-hw/include/irq_session/irq_session.h @@ -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 +#include + +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_ */ diff --git a/base-hw/include/kernel/syscalls.h b/base-hw/include/kernel/syscalls.h index a1f9e2d3d..3e6a4fbd8 100644 --- a/base-hw/include/kernel/syscalls.h +++ b/base-hw/include/kernel/syscalls.h @@ -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); } diff --git a/base-hw/src/base/signal/signal.cc b/base-hw/src/base/signal/signal.cc index 5873c34da..86b599fd1 100644 --- a/base-hw/src/base/signal/signal.cc +++ b/base-hw/src/base/signal/signal.cc @@ -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()); } diff --git a/base-hw/src/core/arndale/platform_support.cc b/base-hw/src/core/arndale/platform_support.cc index 91a49409f..ee4fb12ab 100644 --- a/base-hw/src/core/arndale/platform_support.cc +++ b/base-hw/src/core/arndale/platform_support.cc @@ -16,10 +16,43 @@ #include #include #include - +#include 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[] = diff --git a/base-hw/src/core/imx31/platform_support.cc b/base-hw/src/core/imx31/platform_support.cc index 0eb511047..759ef5f0c 100644 --- a/base-hw/src/core/imx31/platform_support.cc +++ b/base-hw/src/core/imx31/platform_support.cc @@ -15,9 +15,38 @@ #include #include #include +#include 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[] = diff --git a/base-hw/src/core/imx53/platform_support.cc b/base-hw/src/core/imx53/platform_support.cc index 6dbbb16e2..b744c5e69 100644 --- a/base-hw/src/core/imx53/platform_support.cc +++ b/base-hw/src/core/imx53/platform_support.cc @@ -15,9 +15,54 @@ #include #include #include +#include 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[] = diff --git a/base-hw/src/core/include/irq_session_component.h b/base-hw/src/core/include/irq_session_component.h new file mode 100644 index 000000000..58c4d882a --- /dev/null +++ b/base-hw/src/core/include/irq_session_component.h @@ -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 +#include +#include + +namespace Genode +{ + /** + * Backend for IRQ sessions to core + */ + class Irq_session_component + : + public Rpc_object, + public List::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_ */ diff --git a/base-hw/src/core/include/platform.h b/base-hw/src/core/include/platform.h index 6b72b49c6..f953e16ab 100644 --- a/base-hw/src/core/include/platform.h +++ b/base-hw/src/core/include/platform.h @@ -17,6 +17,7 @@ /* Genode includes */ #include #include +#include #include #include @@ -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: diff --git a/base-hw/src/core/irq_session_component.cc b/base-hw/src/core/irq_session_component.cc index ebb9bb406..00d41f584 100644 --- a/base-hw/src/core/irq_session_component.cc +++ b/base-hw/src/core/irq_session_component.cc @@ -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 /* core includes */ +#include #include +#include 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)); } diff --git a/base-hw/src/core/kernel.cc b/base-hw/src/core/kernel.cc index 2d34786a4..b54cfec8d 100644 --- a/base-hw/src/core/kernel.cc +++ b/base-hw/src/core/kernel.cc @@ -25,9 +25,11 @@ /* core includes */ #include #include +#include #include #include #include +#include /* base-hw includes */ #include @@ -42,9 +44,16 @@ extern "C" void CORE_MAIN(); namespace Kernel { + /** + * Return interrupt-controller singleton + */ + Pic * pic() { return unsynchronized_singleton(); } + /* 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; } diff --git a/base-hw/src/core/kernel/irq.cc b/base-hw/src/core/kernel/irq.cc new file mode 100644 index 000000000..1810e9832 --- /dev/null +++ b/base-hw/src/core/kernel/irq.cc @@ -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 +#include + +using namespace Kernel; + +namespace Kernel { Pic * pic(); } + +void Irq::_disable() const { pic()->mask(_id()); } + +void Irq::_enable() const { pic()->unmask(_id()); } diff --git a/base-hw/src/core/kernel/irq.h b/base-hw/src/core/kernel/irq.h new file mode 100644 index 000000000..9cd2a79d1 --- /dev/null +++ b/base-hw/src/core/kernel/irq.h @@ -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 +#include + +/* core includes */ +#include + +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::Item, + public Signal_receiver, + public Signal_context +{ + friend class Genode::Irq; + + private: + + typedef Object_pool 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_ */ diff --git a/base-hw/src/core/kernel/irq_receiver.h b/base-hw/src/core/kernel/irq_receiver.h deleted file mode 100644 index 10769ac9e..000000000 --- a/base-hw/src/core/kernel/irq_receiver.h +++ /dev/null @@ -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 -#include -#include - -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(); } -} - -class Kernel::Irq_receiver : public Object_pool::Item -{ - private: - - typedef Object_pool 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_ */ diff --git a/base-hw/src/core/kernel/signal_receiver.cc b/base-hw/src/core/kernel/signal_receiver.cc index 36060e159..694b84091 100644 --- a/base-hw/src/core/kernel/signal_receiver.cc +++ b/base-hw/src/core/kernel/signal_receiver.cc @@ -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); +} diff --git a/base-hw/src/core/kernel/signal_receiver.h b/base-hw/src/core/kernel/signal_receiver.h index 96c37ae2d..71d32b598 100644 --- a/base-hw/src/core/kernel/signal_receiver.h +++ b/base-hw/src/core/kernel/signal_receiver.h @@ -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 */ diff --git a/base-hw/src/core/kernel/thread.cc b/base-hw/src/core/kernel/thread.cc index 4a1752c5a..69706304b 100644 --- a/base-hw/src/core/kernel/thread.cc +++ b/base-hw/src/core/kernel/thread.cc @@ -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; diff --git a/base-hw/src/core/kernel/thread.h b/base-hw/src/core/kernel/thread.h index 6100c47a9..f55b2d12a 100644 --- a/base-hw/src/core/kernel/thread.h +++ b/base-hw/src/core/kernel/thread.h @@ -19,7 +19,6 @@ #include #include #include -#include #include namespace Genode @@ -56,7 +55,6 @@ class Kernel::Thread public Object, 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: /** diff --git a/base-hw/src/core/panda/platform_support.cc b/base-hw/src/core/panda/platform_support.cc index 6720adc55..2124b0800 100644 --- a/base-hw/src/core/panda/platform_support.cc +++ b/base-hw/src/core/panda/platform_support.cc @@ -16,9 +16,47 @@ #include #include #include +#include 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[] = diff --git a/base-hw/src/core/pbxa9/platform_support.cc b/base-hw/src/core/pbxa9/platform_support.cc index 55ba53c16..0cf7690ac 100644 --- a/base-hw/src/core/pbxa9/platform_support.cc +++ b/base-hw/src/core/pbxa9/platform_support.cc @@ -16,10 +16,46 @@ #include #include #include - +#include 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[] = diff --git a/base-hw/src/core/platform.cc b/base-hw/src/core/platform.cc index 3ad3a689a..5d508999e 100644 --- a/base-hw/src/core/platform.cc +++ b/base-hw/src/core/platform.cc @@ -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 diff --git a/base-hw/src/core/rpi/platform_support.cc b/base-hw/src/core/rpi/platform_support.cc index 3c00c3112..c1441ea9d 100644 --- a/base-hw/src/core/rpi/platform_support.cc +++ b/base-hw/src/core/rpi/platform_support.cc @@ -14,9 +14,38 @@ /* core includes */ #include #include +#include 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[] = diff --git a/base-hw/src/core/target.inc b/base-hw/src/core/target.inc index 7ca866a3d..882139d90 100644 --- a/base-hw/src/core/target.inc +++ b/base-hw/src/core/target.inc @@ -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 \ diff --git a/base-hw/src/core/vea9x4/no_trustzone/platform_support.cc b/base-hw/src/core/vea9x4/no_trustzone/platform_support.cc index b4ff5b4fe..1f68d40b6 100644 --- a/base-hw/src/core/vea9x4/no_trustzone/platform_support.cc +++ b/base-hw/src/core/vea9x4/no_trustzone/platform_support.cc @@ -16,9 +16,46 @@ #include #include #include +#include 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[] = diff --git a/base-hw/src/core/vea9x4/trustzone/platform_support.cc b/base-hw/src/core/vea9x4/trustzone/platform_support.cc index 1b2a6e939..1a0608307 100644 --- a/base-hw/src/core/vea9x4/trustzone/platform_support.cc +++ b/base-hw/src/core/vea9x4/trustzone/platform_support.cc @@ -16,9 +16,45 @@ #include #include #include +#include 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[] =