/* * \brief Fiasco.OC-specific core implementation of IRQ sessions * \author Christian Helmuth * \author Stefan Kalkowski * \author Sebastian Sumpf * \date 2007-09-13 * * FIXME ram quota missing */ /* * Copyright (C) 2007-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. */ /* Genode includes */ #include #include /* core includes */ #include #include #include #include #include /* Fiasco includes */ namespace Fiasco { #include #include #include #include } using namespace Genode; namespace Genode { class Interrupt_handler; class Irq_proxy_component; } /** * Dispatches interrupts from kernel */ class Genode::Interrupt_handler : public Thread<4096> { private: Interrupt_handler() : Thread("irq_handler") { start(); } public: void entry(); static Native_thread handler_cap() { static Interrupt_handler handler; return handler._thread_cap.dst(); } }; /** * Irq_proxy interface implementation */ class Genode::Irq_proxy_component : public Irq_proxy_base { private: Cap_index *_cap; Semaphore _sem; long _trigger; /* interrupt trigger */ long _polarity; /* interrupt polarity */ Native_thread _capability() const { return _cap->kcap(); } protected: bool _associate() { using namespace Fiasco; if (l4_error(l4_factory_create_irq(L4_BASE_FACTORY_CAP, _capability()))) { PERR("l4_factory_create_irq failed!"); return false; } if (l4_error(l4_icu_bind(L4_BASE_ICU_CAP, _irq_number, _capability()))) { PERR("Binding IRQ%ld to the ICU failed", _irq_number); return false; } /* set interrupt mode */ Platform::setup_irq_mode(_irq_number, _trigger, _polarity); if (l4_error(l4_irq_attach(_capability(), _irq_number, Interrupt_handler::handler_cap()))) { PERR("Error attaching to IRQ %ld", _irq_number); return false; } return true; } void _wait_for_irq() { using namespace Fiasco; int err; l4_msgtag_t tag = l4_irq_unmask(_capability()); if ((err = l4_ipc_error(tag, l4_utcb()))) PERR("IRQ unmask: %d\n", err); _sem.down(); } void _ack_irq() { } public: Irq_proxy_component(long irq_number) : 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) { _trigger = trigger; _polarity = polarity; _start(); } bool match_mode(long trigger, long polarity) { if (trigger == Irq_session::TRIGGER_UNCHANGED && polarity == Irq_session::POLARITY_UNCHANGED) return true; if (_trigger < 0 && _polarity < 0) return true; return _trigger == trigger && _polarity == polarity; } long trigger() const { return _trigger; } long polarity() const { return _polarity; } }; /******************************** ** IRQ session implementation ** ********************************/ 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) { 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(); } long irq_trigger = Arg_string::find_arg(args, "irq_trigger").long_value(-1); irq_trigger = irq_trigger == -1 ? 0 : irq_trigger; long irq_polarity = Arg_string::find_arg(args, "irq_polarity").long_value(-1); irq_polarity = irq_polarity == -1 ? 0 : irq_polarity; /* * temorary 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_number, irq_alloc))) { PERR("No proxy for IRQ %lu found", irq_number); throw Root::Unavailable(); } /* 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", 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 (!_proxy->add_sharer()) throw Root::Unavailable(); /* initialize capability */ _irq_cap = _ep.manage(this); } void Irq_session_component::wait_for_irq() { _proxy->wait_for_irq(); } Irq_session_component::~Irq_session_component() { _proxy->remove_sharer(); } Irq_signal Irq_session_component::signal() { PDBG("not implemented;"); return Irq_signal(); } /*************************************** ** Interrupt handler implemtentation ** ***************************************/ /* Build with frame pointer to make GDB backtraces work. See issue #1061. */ __attribute__((optimize("-fno-omit-frame-pointer"))) __attribute__((noinline)) void Interrupt_handler::entry() { using namespace Fiasco; int err; l4_msgtag_t tag; l4_umword_t label; while (true) { tag = l4_ipc_wait(l4_utcb(), &label, L4_IPC_NEVER); if ((err = l4_ipc_error(tag, l4_utcb()))) PERR("IRQ receive: %d\n", err); else { Irq_proxy_component *proxy; proxy = Irq_proxy_component::get_irq_proxy(label); if (proxy) proxy->semaphore()->up(); } } }