diff --git a/base-foc/src/core/arm/platform_arm.cc b/base-foc/src/core/arm/platform_arm.cc index 33877c19a..c62dbca09 100644 --- a/base-foc/src/core/arm/platform_arm.cc +++ b/base-foc/src/core/arm/platform_arm.cc @@ -15,4 +15,4 @@ void Genode::Platform::_setup_io_port_alloc() { } -void Genode::Platform::setup_irq_mode(unsigned irq_number) { } +void Genode::Platform::setup_irq_mode(unsigned, unsigned, unsigned) { } diff --git a/base-foc/src/core/include/arm/irq_proxy_component.h b/base-foc/src/core/include/arm/irq_proxy_component.h new file mode 100644 index 000000000..194736df5 --- /dev/null +++ b/base-foc/src/core/include/arm/irq_proxy_component.h @@ -0,0 +1,29 @@ +/** + * \brief Base class for shared interrupts on ARM + * \author Sebastian Sumpf + * \date 2012-10-05 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _CORE__INCLUDE__ARM__IRQ_PROXY_COMPONENT_H_ +#define _CORE__INCLUDE__ARM__IRQ_PROXY_COMPONENT_H_ + +#include + +namespace Genode { + +/** + * On ARM we disable shared interrupts + */ +typedef Irq_proxy_single Irq_proxy_base; + +} + +#endif /* _CORE__INCLUDE__ARM__IRQ_PROXY_COMPONENT_H_ */ + diff --git a/base-foc/src/core/include/irq_session_component.h b/base-foc/src/core/include/irq_session_component.h index 02f7e6b76..06198b3ab 100644 --- a/base-foc/src/core/include/irq_session_component.h +++ b/base-foc/src/core/include/irq_session_component.h @@ -23,48 +23,13 @@ namespace Genode { + class Irq_proxy_component; + class Irq_session_component : public Rpc_object, public List::Element { private: - class Interrupt : public Avl_node - { - private: - - Cap_index* _cap; - Semaphore _sem; - - public: - - unsigned number; - - Interrupt(); - - bool higher(Interrupt *n); - Interrupt* find_by_num(unsigned num); - - Native_thread capability() { return _cap->kcap(); } - Semaphore* semaphore() { return &_sem; } - }; - - - class Interrupt_handler : public Thread<4096> - { - private: - - Interrupt_handler() { start(); } - - void entry(); - - public: - - static Native_thread handler_cap(); - }; - - - Interrupt _irq; - Range_allocator *_irq_alloc; /* * Each IRQ session uses a dedicated server activation @@ -73,8 +38,7 @@ namespace Genode { Rpc_entrypoint _ep; Irq_session_capability _irq_cap; - - static Avl_tree* _irqs(); + Irq_proxy_component *_proxy; public: diff --git a/base-foc/src/core/include/platform.h b/base-foc/src/core/include/platform.h index 947707505..6c47eebe4 100644 --- a/base-foc/src/core/include/platform.h +++ b/base-foc/src/core/include/platform.h @@ -129,9 +129,10 @@ namespace Genode { Core_pager *core_pager(); /** - * Set interrupt mode (e.g., level or edge) + * Set interrupt trigger/polarity (e.g., level or edge, high or low) */ - static void setup_irq_mode(unsigned irq_number); + static void setup_irq_mode(unsigned irq_number, unsigned trigger, + unsigned polarity); /** * Constructor diff --git a/base-foc/src/core/include/x86/irq_proxy_component.h b/base-foc/src/core/include/x86/irq_proxy_component.h new file mode 100644 index 000000000..dc37d23d9 --- /dev/null +++ b/base-foc/src/core/include/x86/irq_proxy_component.h @@ -0,0 +1,24 @@ +/** + * \brief Base class for shared interrupts on x86 + * \author Sebastian Sumpf + * \date 2012-10-05 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _CORE__INCLUDE__X86__IRQ_PROXY_COMPONENT_H_ +#define _CORE__INCLUDE__X86__IRQ_PROXY_COMPONENT_H_ + +#include + +namespace Genode { + typedef Irq_proxy > Irq_proxy_base; +} + +#endif /* _CORE__INCLUDE__X86__IRQ_PROXY_COMPONENT_H_ */ + diff --git a/base-foc/src/core/irq_session_component.cc b/base-foc/src/core/irq_session_component.cc index 72e8bb14d..85892f30f 100644 --- a/base-foc/src/core/irq_session_component.cc +++ b/base-foc/src/core/irq_session_component.cc @@ -2,6 +2,7 @@ * \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 @@ -20,6 +21,7 @@ /* core includes */ #include +#include #include #include #include @@ -34,36 +36,197 @@ namespace Fiasco { using namespace Genode; +namespace Genode { + class Interrupt_handler; + class Irq_proxy_component; +} -Irq_session_component::Interrupt* -Irq_session_component::Interrupt::find_by_num(unsigned num) +/** + * Dispatches interrupts from kernel + */ +class Genode::Interrupt_handler : public Thread<4096> { - if (number == num) return this; + private: - Interrupt *n = Avl_node::child(num > number); - return n ? n->find_by_num(num) : 0; + Interrupt_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); } -bool Irq_session_component::Interrupt::higher(Irq_session_component::Interrupt *n) +void Irq_session_component::wait_for_irq() { - return n->number > number; + _proxy->wait_for_irq(); } -Irq_session_component::Interrupt::Interrupt() -: _cap(cap_map()->insert(platform_specific()->cap_id_alloc()->alloc())), - _sem(), number(0) {} - - -Native_thread Irq_session_component::Interrupt_handler::handler_cap() +Irq_session_component::~Irq_session_component() { - static Interrupt_handler handler; - return handler._thread_cap.dst(); + PERR("Implement me, immediately!"); } -void Irq_session_component::Interrupt_handler::entry() +/*************************************** + ** Interrupt handler implemtentation ** + ***************************************/ + +void Interrupt_handler::entry() { using namespace Fiasco; @@ -76,81 +239,11 @@ void Irq_session_component::Interrupt_handler::entry() if ((err = l4_ipc_error(tag, l4_utcb()))) PERR("IRQ receive: %d\n", err); else { - Interrupt *intr = _irqs()->first(); - if (intr) { - intr = intr->find_by_num(label); - if (intr) - intr->semaphore()->up(); - } + Irq_proxy_component *proxy; + proxy = Irq_proxy_component::get_irq_proxy(label); + + if (proxy) + proxy->semaphore()->up(); } } } - - -Avl_tree* Irq_session_component::_irqs() -{ - static Avl_tree irqs; - return &irqs; -} - - -Irq_session_component::Irq_session_component(Cap_session *cap_session, - Range_allocator *irq_alloc, - const char *args) -: - _irq_alloc(irq_alloc), - _ep(cap_session, STACK_SIZE, "irqctrl") -{ - using namespace Fiasco; - - long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1); - if ((irq_number == -1) || _irq_alloc->alloc_addr(1, irq_number)) { - PERR("Unavailable IRQ %lx requested", irq_number); - throw Root::Invalid_args(); - } - - /* - * temorary hack for fiasco.oc using the local-apic, - * where old pic-line 0 maps to 2 - */ - if (irq_number == 0) - irq_number = 2; - - _irq.number = irq_number; - Irq_session_component::_irqs()->insert(&_irq); - - if (l4_error(l4_factory_create_irq(L4_BASE_FACTORY_CAP, _irq.capability()))) - PERR("l4_factory_create_irq failed!"); - - if (l4_error(l4_icu_bind(L4_BASE_ICU_CAP, irq_number, _irq.capability()))) - PERR("Binding IRQ%ld to the ICU failed", irq_number); - - /* set interrupt mode */ - Platform::setup_irq_mode(irq_number); - - if (l4_error(l4_irq_attach(_irq.capability(), irq_number, - Interrupt_handler::handler_cap()))) - PERR("Error attaching to IRQ %ld", irq_number); - - /* initialize capability */ - _irq_cap = _ep.manage(this); -} - - -void Irq_session_component::wait_for_irq() -{ - using namespace Fiasco; - - int err; - l4_msgtag_t tag = l4_irq_unmask(_irq.capability()); - if ((err = l4_ipc_error(tag, l4_utcb()))) - PERR("IRQ unmask: %d\n", err); - - _irq.semaphore()->down(); -} - - -Irq_session_component::~Irq_session_component() -{ - PERR("Implement me, immediately!"); -} diff --git a/base-foc/src/core/panda/target.mk b/base-foc/src/core/panda/target.mk index a5748bd52..194792be1 100644 --- a/base-foc/src/core/panda/target.mk +++ b/base-foc/src/core/panda/target.mk @@ -4,6 +4,8 @@ LD_TEXT_ADDR = 0x80140000 REQUIRES += arm foc_panda SRC_CC += arm/platform_arm.cc +INC_DIR += $(REP_DIR)/src/core/include/arm + vpath io_port_session_component.cc $(GEN_CORE_DIR)/arm diff --git a/base-foc/src/core/pbxa9/target.mk b/base-foc/src/core/pbxa9/target.mk index e36656912..78d8e90f3 100644 --- a/base-foc/src/core/pbxa9/target.mk +++ b/base-foc/src/core/pbxa9/target.mk @@ -2,6 +2,7 @@ include $(PRG_DIR)/../target.inc REQUIRES += arm foc_pbxa9 SRC_CC += arm/platform_arm.cc +INC_DIR += $(REP_DIR)/src/core/include/arm LD_TEXT_ADDR = 0x70490000 diff --git a/base-foc/src/core/vea9x4/target.mk b/base-foc/src/core/vea9x4/target.mk index caec1ea90..5ebecfc44 100644 --- a/base-foc/src/core/vea9x4/target.mk +++ b/base-foc/src/core/vea9x4/target.mk @@ -2,6 +2,7 @@ include $(PRG_DIR)/../target.inc REQUIRES += arm foc_vea9x4 SRC_CC += arm/platform_arm.cc +INC_DIR += $(REP_DIR)/src/core/include/arm LD_TEXT_ADDR = 0x60490000 diff --git a/base-foc/src/core/x86/platform_x86.cc b/base-foc/src/core/x86/platform_x86.cc index a788bedad..65fc402b7 100644 --- a/base-foc/src/core/x86/platform_x86.cc +++ b/base-foc/src/core/x86/platform_x86.cc @@ -14,6 +14,7 @@ /* Genode includes */ #include +#include #include "platform.h" #include "util.h" @@ -45,12 +46,28 @@ void Genode::Platform::_setup_io_port_alloc() } -void Genode::Platform::setup_irq_mode(unsigned irq_number) +void Genode::Platform::setup_irq_mode(unsigned irq_number, unsigned trigger, + unsigned polarity) { using namespace Fiasco; - /* set IRQ below 16 to edge/high and others to level/low */ - l4_umword_t mode = irq_number < 16 ? L4_IRQ_F_POS_EDGE : L4_IRQ_F_LEVEL_LOW; + /* + * Translate ACPI interrupt mode (trigger/polarity) to Fiasco APIC + * values. Default is edge/high for IRQs < 16 and level low for IRQs > 16 + */ + l4_umword_t mode; + mode = (trigger == Irq_session::TRIGGER_LEVEL) || + (irq_number > 15 && trigger == Irq_session::TRIGGER_UNCHANGED) + ? L4_IRQ_F_LEVEL : L4_IRQ_F_EDGE; + + mode |= (polarity == Irq_session::POLARITY_LOW) || + (irq_number > 15 && polarity == Irq_session::POLARITY_UNCHANGED) + ? L4_IRQ_F_NEG : L4_IRQ_F_POS; + + + /* + * Set mode + */ if (l4_error(l4_icu_set_mode(L4_BASE_ICU_CAP, irq_number, mode))) PERR("Setting mode for IRQ%u failed", irq_number); } diff --git a/base-foc/src/core/x86/target.mk b/base-foc/src/core/x86/target.mk index 6bb51354f..cca08a84b 100644 --- a/base-foc/src/core/x86/target.mk +++ b/base-foc/src/core/x86/target.mk @@ -2,6 +2,7 @@ include $(PRG_DIR)/../target.inc REQUIRES += x86 SRC_CC += x86/platform_x86.cc +INC_DIR += $(REP_DIR)/src/core/include/x86 vpath io_port_session_component.cc $(GEN_CORE_DIR)/x86 diff --git a/base-nova/src/base/pager/pager.cc b/base-nova/src/base/pager/pager.cc index fb7dadb40..ac3e0433d 100644 --- a/base-nova/src/base/pager/pager.cc +++ b/base-nova/src/base/pager/pager.cc @@ -214,6 +214,9 @@ Pager_object::Pager_object(unsigned long badge) _state.singlestep = false; _state.sel_client_ec = Native_thread::INVALID_INDEX; + /* creates local EC */ + Thread_base::start(); + /* Create portal for exception handlers 0x0 - 0xd */ for (unsigned i = 0; i < PT_SEL_PAGE_FAULT; i++) { res = create_pt(exc_pt_sel() + i, pd_sel, _tid.ec_sel, diff --git a/base-nova/src/base/server/server.cc b/base-nova/src/base/server/server.cc index 635d24b4b..998e4d4d6 100644 --- a/base-nova/src/base/server/server.cc +++ b/base-nova/src/base/server/server.cc @@ -243,6 +243,11 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size, throw Cpu_session::Thread_creation_failed(); _tid.ec_sel = ec_cap.local_name(); } + else + /** + * Required for core threads (creates local EC) + */ + Thread_base::start(); _rcv_buf.rcv_prepare_pt_sel_window((Nova::Utcb *)&_context->utcb); diff --git a/base-nova/src/core/include/irq_session_component.h b/base-nova/src/core/include/irq_session_component.h index 3f7b51cc7..b65d25b20 100644 --- a/base-nova/src/core/include/irq_session_component.h +++ b/base-nova/src/core/include/irq_session_component.h @@ -22,20 +22,20 @@ namespace Genode { + class Irq_proxy_component; + class Irq_session_component : public Rpc_object, public List::Element { private: - unsigned _irq_number; - Range_allocator *_irq_alloc; - /* * Each IRQ session uses a dedicated server activation */ enum { STACK_SIZE = 2048 }; Rpc_entrypoint _ep; Irq_session_capability _irq_cap; + Irq_proxy_component *_proxy; public: diff --git a/base-nova/src/core/include/nova_util.h b/base-nova/src/core/include/nova_util.h index 7143c639a..8f17aa6ff 100644 --- a/base-nova/src/core/include/nova_util.h +++ b/base-nova/src/core/include/nova_util.h @@ -137,7 +137,7 @@ inline int map_local(Nova::Utcb *utcb, if (verbose_local_map) Genode::printf("::map_local: order %zx %lx:%lx %lx:%lx\n", - order, from_curr, from_end, to_curr, to_end); + order, from_curr, from_end, to_curr, to_end); int const res = map_local(utcb, Mem_crd((from_curr >> 12), order - get_page_size_log2(), rwx), diff --git a/base-nova/src/core/irq_session_component.cc b/base-nova/src/core/irq_session_component.cc index d994b18a0..f2371be24 100644 --- a/base-nova/src/core/irq_session_component.cc +++ b/base-nova/src/core/irq_session_component.cc @@ -14,10 +14,13 @@ /* Genode includes */ #include +#include /* core includes */ #include +#include #include +#include /* NOVA includes */ #include @@ -26,11 +29,129 @@ using namespace Genode; +namespace Genode { + class Irq_proxy_component; +} + + +/** + * Global worker (i.e. thread with SC) + */ +class Irq_thread : public Thread_base +{ + private: + + static void _thread_start() + { + Thread_base::myself()->entry(); + sleep_forever(); + } + + public: + + Irq_thread(char const *name) : Thread_base(name, 1024 * sizeof(addr_t)) { } + + /** + * Create global EC, associate it to SC + */ + void start() + { + using namespace Nova; + addr_t pd_sel = Platform_pd::pd_core_sel(); + addr_t utcb = reinterpret_cast(&_context->utcb); + + /* + * Put IP on stack, it will be read from core pager in platform.cc + */ + addr_t *sp = reinterpret_cast(_context->stack - sizeof(addr_t)); + *sp = reinterpret_cast(_thread_start); + + /* create global EC */ + enum { CPU_NO = 0, GLOBAL = true }; + uint8_t res = create_ec(_tid.ec_sel, pd_sel, CPU_NO, + utcb, (mword_t)sp, _tid.exc_pt_sel, GLOBAL); + if (res != NOVA_OK) { + PERR("%p - create_ec returned %d", this, res); + throw Cpu_session::Thread_creation_failed(); + } + + /* map startup portal from main thread */ + map_local((Utcb *)Thread_base::myself()->utcb(), + Obj_crd(PT_SEL_STARTUP, 0), + Obj_crd(_tid.exc_pt_sel + PT_SEL_STARTUP, 0)); + + /* create SC */ + unsigned sc_sel = cap_selector_allocator()->alloc(); + res = create_sc(sc_sel, pd_sel, _tid.ec_sel, Qpd()); + if (res != NOVA_OK) { + PERR("%p - create_sc returned returned %d", this, res); + throw Cpu_session::Thread_creation_failed(); + } + } +}; + + +/** + * Irq_proxy interface implementation + */ +class Genode::Irq_proxy_component : public Irq_proxy +{ + private: + + long _irq_sel; /* IRQ cap selector */ + + protected: + + bool _associate() + { + /* alloc slector where IRQ will be mapped */ + _irq_sel = cap_selector_allocator()->alloc(); + + /* since we run in APIC mode translate IRQ 0 (PIT) to 2 */ + if (!_irq_number) + _irq_number = 2; + + /* map IRQ number to selector */ + int ret = map_local((Nova::Utcb *)Thread_base::myself()->utcb(), + Nova::Obj_crd(platform_specific()->gsi_base_sel() + _irq_number, 0), + Nova::Obj_crd(_irq_sel, 0), + true); + if (ret) { + PERR("Could not map IRQ %ld", _irq_number); + return false; + } + + /* assign IRQ to CPU */ + enum { CPU = 0 }; + Nova::assign_gsi(_irq_sel, 0, CPU); + + return true; + } + + void _wait_for_irq() + { + if (Nova::sm_ctrl(_irq_sel, Nova::SEMAPHORE_DOWN)) + nova_die(); + } + + void _ack_irq() { } + + public: + + Irq_proxy_component(long irq_number) : Irq_proxy(irq_number) + { + _start(); + } +}; + + +typedef Irq_proxy Proxy; + void Irq_session_component::wait_for_irq() { - if (Nova::sm_ctrl(_irq_number, Nova::SEMAPHORE_DOWN)) - nova_die(); + _proxy->wait_for_irq(); + /* interrupt ocurred and proxy woke us up */ } @@ -38,36 +159,19 @@ Irq_session_component::Irq_session_component(Cap_session *cap_session, Range_allocator *irq_alloc, const char *args) : - _irq_alloc(irq_alloc), _ep(cap_session, STACK_SIZE, "irq") { long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1); - if (irq_number == -1 || !irq_alloc || - irq_alloc->alloc_addr(1, irq_number) != Range_allocator::ALLOC_OK) { + + /* check if IRQ thread was started before */ + _proxy = Proxy::get_irq_proxy(irq_number, irq_alloc); + if (irq_number == -1 || !_proxy) { PERR("Unavailable IRQ %lx requested", irq_number); - throw Root::Invalid_args(); - } - - /* alloc slector where IRQ will be mapped */ - _irq_number = cap_selector_allocator()->alloc(); - - /* since we run in APIC mode translate IRQ 0 (PIT) to 2 */ - if (!irq_number) - irq_number = 2; - - /* map IRQ number to selector */ - int ret = map_local((Nova::Utcb *)Thread_base::myself()->utcb(), - Nova::Obj_crd(platform_specific()->gsi_base_sel() + irq_number, 0), - Nova::Obj_crd(_irq_number, 0), - true); - if (ret) { - PERR("Could not map IRQ %d", _irq_number); throw Root::Unavailable(); } - /* assign IRQ to CPU */ - enum { CPU = 0 }; - Nova::assign_gsi(_irq_number, 0, CPU); + _proxy->add_sharer(); + /* initialize capability */ _irq_cap = _ep.manage(this); } diff --git a/base-nova/src/core/platform.cc b/base-nova/src/core/platform.cc index 9517fd82d..f00d35c9d 100644 --- a/base-nova/src/core/platform.cc +++ b/base-nova/src/core/platform.cc @@ -134,24 +134,44 @@ static void page_fault_handler() } +static addr_t core_pager_stack_top() +{ + enum { STACK_SIZE = 4*1024 }; + static char stack[STACK_SIZE]; + return (addr_t)&stack[STACK_SIZE - sizeof(addr_t)]; +} + + +/** + * Startup handler for core threads + */ +static void startup_handler() +{ + Utcb *utcb = (Utcb *)CORE_PAGER_UTCB_ADDR; + + /* initial IP is on stack */ + utcb->ip = *reinterpret_cast(utcb->sp); + utcb->mtd = Mtd::EIP | Mtd::ESP; + utcb->set_msg_word(0); + + reply((void*)core_pager_stack_top()); +} + + static void init_core_page_fault_handler() { /* create echo EC */ enum { - STACK_SIZE = 4*1024, CPU_NO = 0, GLOBAL = false, EXC_BASE = 0 }; - static char stack[STACK_SIZE]; - - addr_t sp = (addr_t)&stack[STACK_SIZE - sizeof(addr_t)]; addr_t ec_sel = cap_selector_allocator()->alloc(); uint8_t ret = create_ec(ec_sel, __core_pd_sel, CPU_NO, - CORE_PAGER_UTCB_ADDR, (addr_t)sp, EXC_BASE, - GLOBAL); + CORE_PAGER_UTCB_ADDR, core_pager_stack_top(), + EXC_BASE, GLOBAL); if (ret) PDBG("create_ec returned %u", ret); @@ -159,6 +179,11 @@ static void init_core_page_fault_handler() create_pt(PT_SEL_PAGE_FAULT, __core_pd_sel, ec_sel, Mtd(Mtd::QUAL | Mtd::ESP | Mtd::EIP), (addr_t)page_fault_handler); + + /* startup portal for global core threads */ + create_pt(PT_SEL_STARTUP, __core_pd_sel, ec_sel, + Mtd(Mtd::EIP | Mtd::ESP), + (addr_t)startup_handler); } diff --git a/base-nova/src/core/thread_start.cc b/base-nova/src/core/thread_start.cc index e0d2ccef0..dbca087d1 100644 --- a/base-nova/src/core/thread_start.cc +++ b/base-nova/src/core/thread_start.cc @@ -30,13 +30,13 @@ using namespace Genode; -/** - * This function is called for constructing server activations and pager - * objects. It allocates capability selectors for the thread's execution - * context and a synchronization-helper semaphore needed for 'Lock'. - */ void Thread_base::_init_platform_thread() { + /* + * This function is called for constructing server activations and pager + * objects. It allocates capability selectors for the thread's execution + * context and a synchronization-helper semaphore needed for 'Lock'. + */ using namespace Nova; _tid.ec_sel = cap_selector_allocator()->alloc(); @@ -50,18 +50,6 @@ void Thread_base::_init_platform_thread() PERR("create_sm returned %u", res); throw Cpu_session::Thread_creation_failed(); } - - addr_t sp = reinterpret_cast(&_context->stack[-4]); - addr_t utcb = reinterpret_cast(&_context->utcb); - - /* create local EC */ - enum { CPU_NO = 0, GLOBAL = false }; - res = create_ec(_tid.ec_sel, pd_sel, CPU_NO, - utcb, sp, _tid.exc_pt_sel, GLOBAL); - if (res != NOVA_OK) { - PERR("%p - create_ec returned %d", this, res); - throw Cpu_session::Thread_creation_failed(); - } } @@ -84,10 +72,26 @@ void Thread_base::_deinit_platform_thread() void Thread_base::start() { /* - * On NOVA, core never starts regular threads. + * On NOVA, core almost nerver starts regular threads. This simply creates a + * local EC */ + using namespace Nova; + + addr_t sp = reinterpret_cast(&_context->stack[-4]); + addr_t utcb = reinterpret_cast(&_context->utcb); + addr_t pd_sel = Platform_pd::pd_core_sel(); + + /* create local EC */ + enum { CPU_NO = 0, GLOBAL = false }; + uint8_t res = create_ec(_tid.ec_sel, pd_sel, CPU_NO, + utcb, sp, _tid.exc_pt_sel, GLOBAL); + if (res != NOVA_OK) { + PERR("%p - create_ec returned %d", this, res); + throw Cpu_session::Thread_creation_failed(); + } } + void Thread_base::cancel_blocking() { using namespace Nova; diff --git a/base-okl4/src/core/irq_session_component.cc b/base-okl4/src/core/irq_session_component.cc index 9d2449b0c..b713dce66 100644 --- a/base-okl4/src/core/irq_session_component.cc +++ b/base-okl4/src/core/irq_session_component.cc @@ -12,14 +12,10 @@ * under the terms of the GNU General Public License version 2. */ -/* Genode includes */ -#include -#include -#include +#include /* core includes */ #include -#include /* OKL4 includes */ namespace Okl4 { extern "C" { @@ -30,8 +26,14 @@ namespace Okl4 { extern "C" { #include } } -using namespace Genode; using namespace Okl4; +using namespace Genode; + + +/** + * Proxy class with generic thread + */ +typedef Irq_proxy > Proxy; /* XXX move this functionality to a central place instead of duplicating it */ @@ -43,55 +45,12 @@ static inline Okl4::L4_ThreadId_t thread_get_my_global_id() } -/****************************** - ** Shared-interrupt support ** - ******************************/ - -class Irq_blocker : public List::Element -{ - private: - - Lock _wait_lock; - - public: - - Irq_blocker() : _wait_lock(Lock::LOCKED) { } - - void block() { _wait_lock.lock(); } - void unblock() { _wait_lock.unlock(); } -}; - - -/* - * Proxy thread that associates to the interrupt and unblocks waiting irqctrl - * threads. Maybe, we should utilize our signals for interrupt delivery... - * - * XXX resources are not accounted as the interrupt is shared +/** + * Platform-specific proxy code */ -class Irq_proxy : public Thread<0x1000>, - public List::Element +class Irq_proxy_component : public Proxy { - private: - - char _name[32]; - Lock _startup_lock; - - long _irq_number; - - Lock _mutex; /* protects this object */ - int _num_sharers; /* number of clients sharing this IRQ */ - Semaphore _sleep; /* wake me up if aspired blockers return */ - List _blocker_list; - int _num_blockers; /* number of currently blocked clients */ - bool _woken_up; /* client decided to wake me up - - this prevents multiple wakeups - to happen during initialization */ - - const char *_construct_name(long irq_number) - { - snprintf(_name, sizeof(_name), "irqproxy%02lx", irq_number); - return _name; - } + protected: bool _associate() { @@ -126,126 +85,28 @@ class Irq_proxy : public Thread<0x1000>, return true; } - void _loop() + void _wait_for_irq() { - /* wait for first blocker */ - _sleep.down(); + /* wait for asynchronous interrupt notification */ + L4_ThreadId_t partner = L4_nilthread; + L4_ReplyWait(partner, &partner); + } - while (1) { - /* wait for asynchronous interrupt notification */ - L4_ThreadId_t partner = L4_nilthread; - L4_ReplyWait(partner, &partner); - - { - Lock::Guard lock_guard(_mutex); - - /* inform blocked clients */ - Irq_blocker *b; - while ((b = _blocker_list.first())) { - _blocker_list.remove(b); - b->unblock(); - } - - /* reset blocker state */ - _num_blockers = 0; - _woken_up = false; - } - - /* - * We must wait for all clients to ack their interrupt, - * otherwise level-triggered interrupts will occur immediately - * after acknowledgement. That's an inherent security problem - * with shared IRQs and induces problems with dynamic driver - * load and unload. - */ - _sleep.down(); - - /* acknowledge previous interrupt */ - L4_LoadMR(0, _irq_number); - L4_AcknowledgeInterrupt(0, 0); - } + void _ack_irq() + { + L4_LoadMR(0, _irq_number); + L4_AcknowledgeInterrupt(0, 0); } public: - Irq_proxy(long irq_number) - : - Thread<0x1000>(_construct_name(irq_number)), - _startup_lock(Lock::LOCKED), _irq_number(irq_number), - _mutex(Lock::UNLOCKED), _num_sharers(0), _num_blockers(0), _woken_up(false) + Irq_proxy_component(long irq_number) : Irq_proxy(irq_number) { - start(); - _startup_lock.lock(); - } - - /** - * Thread interface - */ - void entry() - { - if (_associate()) { - _startup_lock.unlock(); - _loop(); - } - } - - /** - * Block until interrupt occured - */ - void wait_for_irq() - { - Irq_blocker blocker; - { - Lock::Guard lock_guard(_mutex); - - _blocker_list.insert(&blocker); - _num_blockers++; - - /* - * The proxy thread is woken up if no client woke it up before - * and this client is the last aspired blocker. - */ - if (!_woken_up && _num_blockers == _num_sharers) { - _sleep.up(); - _woken_up = true; - } - } - blocker.block(); - } - - long irq_number() const { return _irq_number; } - - void add_sharer() - { - Lock::Guard lock_guard(_mutex); - ++_num_sharers; + _start(); } }; -static Irq_proxy *get_irq_proxy(long irq_number, Range_allocator *irq_alloc = 0) -{ - static List proxies; - static Lock proxies_lock; - - Lock::Guard lock_guard(proxies_lock); - - /* lookup proxy in database */ - for (Irq_proxy *p = proxies.first(); p; p = p->next()) - if (p->irq_number() == irq_number) - return p; - - /* try to create proxy */ - if (!irq_alloc || irq_alloc->alloc_addr(1, irq_number) != Range_allocator::ALLOC_OK) - return 0; - - Irq_proxy *new_proxy = new (env()->heap()) Irq_proxy(irq_number); - proxies.insert(new_proxy); - - return new_proxy; -} - - /*************************** ** IRQ session component ** ***************************/ @@ -259,7 +120,7 @@ bool Irq_session_component::Irq_control_component::associate_to_irq(unsigned irq void Irq_session_component::wait_for_irq() { /* block at interrupt proxy */ - Irq_proxy *p = get_irq_proxy(_irq_number); + Proxy *p = Proxy::get_irq_proxy(_irq_number); if (!p) { PERR("Expected to find IRQ proxy for IRQ %02x", _irq_number); return; @@ -293,7 +154,7 @@ Irq_session_component::Irq_session_component(Cap_session *cap_session, } /* check if IRQ thread was started before */ - Irq_proxy *irq_proxy = get_irq_proxy(irq_number, irq_alloc); + Proxy *irq_proxy = Proxy::get_irq_proxy(irq_number, irq_alloc); if (!irq_proxy) { PERR("unavailable IRQ %lx requested", irq_number);