From 0188b08f6a3128838ab5e411b0fe1cf6c0ba84ed Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Fri, 3 Apr 2015 17:22:16 +0200 Subject: [PATCH] hw: construct kernel irq objects on demand Ref #1443 --- .../src/core/include/irq_session_component.h | 2 +- .../src/core/include/kernel/core_interface.h | 24 ++++++++++++ repos/base-hw/src/core/include/kernel/irq.h | 38 +++++-------------- .../base-hw/src/core/include/kernel/thread.h | 2 + .../base-hw/src/core/irq_session_component.cc | 18 ++++++--- repos/base-hw/src/core/kernel/kernel.cc | 18 --------- repos/base-hw/src/core/kernel/thread.cc | 10 +++++ repos/base-hw/src/core/platform.cc | 7 +++- repos/base-hw/src/core/spec/arm_gic/pic.cc | 1 + repos/base-hw/src/core/spec/arndale/pic.cc | 1 + 10 files changed, 67 insertions(+), 54 deletions(-) diff --git a/repos/base-hw/src/core/include/irq_session_component.h b/repos/base-hw/src/core/include/irq_session_component.h index 204a71d1c..ee1c1e91f 100644 --- a/repos/base-hw/src/core/include/irq_session_component.h +++ b/repos/base-hw/src/core/include/irq_session_component.h @@ -31,10 +31,10 @@ namespace Genode { private: - unsigned _irq_number; Range_allocator * const _irq_alloc; Irq_session_capability _cap; Irq_signal _signal; + Genode::uint8_t _kernel_object[sizeof(Kernel::User_irq)]; public: diff --git a/repos/base-hw/src/core/include/kernel/core_interface.h b/repos/base-hw/src/core/include/kernel/core_interface.h index d0c3a2dd1..99262b166 100644 --- a/repos/base-hw/src/core/include/kernel/core_interface.h +++ b/repos/base-hw/src/core/include/kernel/core_interface.h @@ -24,6 +24,7 @@ namespace Kernel class Signal_receiver; class Signal_context; class Vm; + class User_irq; addr_t mode_transition_base(); size_t mode_transition_size(); @@ -54,6 +55,8 @@ namespace Kernel constexpr Call_arg call_id_pause_vm() { return 29; } constexpr Call_arg call_id_pause_thread() { return 30; } constexpr Call_arg call_id_delete_vm() { return 31; } + constexpr Call_arg call_id_new_irq() { return 32; } + constexpr Call_arg call_id_delete_irq() { return 33; } /** * Create a domain @@ -346,6 +349,27 @@ namespace Kernel { return call(call_id_pause_vm(), (Call_arg) vm); } + + /** + * Create an interrupt object + * + * \param p memory donation for the irq object + * \param irq_nr interrupt number + */ + inline void new_irq(addr_t const p, unsigned irq_nr) + { + call(call_id_new_irq(), (Call_arg) p, irq_nr); + } + + /** + * Destruct an interrupt object + * + * \param irq pointer to interrupt kernel object + */ + inline void delete_irq(User_irq * const irq) + { + call(call_id_delete_irq(), (Call_arg) irq); + } } #endif /* _KERNEL__CORE_INTERFACE_H_ */ diff --git a/repos/base-hw/src/core/include/kernel/irq.h b/repos/base-hw/src/core/include/kernel/irq.h index 22cd996b1..5273eeff3 100644 --- a/repos/base-hw/src/core/include/kernel/irq.h +++ b/repos/base-hw/src/core/include/kernel/irq.h @@ -113,16 +113,6 @@ class Kernel::User_irq */ static Irq::Pool * _pool(); - /** - * 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(); } - /************************ ** Signal_ack_handler ** @@ -145,6 +135,16 @@ class Kernel::User_irq Signal_context::ack_handler(this); } + /** + * Get kernel name of the interrupt-signal receiver + */ + unsigned receiver_id() const { return Signal_receiver::Object::id(); } + + /** + * Get kernel name of the interrupt-signal context + */ + unsigned context_id() const { return Signal_context::Object::id(); } + /** * Handle occurence of the interrupt */ @@ -154,24 +154,6 @@ class Kernel::User_irq disable(); } - /** - * Get information that enables a user to handle an interrupt - * - * \param irq_id kernel name of targeted interrupt - */ - static Genode::Irq_signal signal(unsigned const irq_id) - { - typedef Genode::Irq_signal Irq_signal; - static Irq_signal const invalid = { 0, 0 }; - User_irq * const irq = - dynamic_cast(_pool()->object(irq_id)); - if (irq) { - Irq_signal s = { irq->_receiver_id(), irq->_context_id() }; - return s; - } - return invalid; - } - /** * Handle occurence of an interrupt * diff --git a/repos/base-hw/src/core/include/kernel/thread.h b/repos/base-hw/src/core/include/kernel/thread.h index e7c1df3f8..1c59a5ca5 100644 --- a/repos/base-hw/src/core/include/kernel/thread.h +++ b/repos/base-hw/src/core/include/kernel/thread.h @@ -237,6 +237,8 @@ class Kernel::Thread void _call_pause_vm(); void _call_access_thread_regs(); void _call_route_thread_event(); + void _call_new_irq(); + void _call_delete_irq(); /*************************** diff --git a/repos/base-hw/src/core/irq_session_component.cc b/repos/base-hw/src/core/irq_session_component.cc index 529a4acad..561dca7dd 100644 --- a/repos/base-hw/src/core/irq_session_component.cc +++ b/repos/base-hw/src/core/irq_session_component.cc @@ -42,22 +42,28 @@ Irq_signal Irq_session_component::signal() { return _signal; } Irq_session_component::~Irq_session_component() { + using namespace Kernel; + irq_session_ep()->dissolve(this); - _irq_alloc->free((void *)(addr_t)_irq_number); + User_irq * kirq = reinterpret_cast(&_kernel_object); + _irq_alloc->free((void *)(addr_t)static_cast(kirq)->id()); + Kernel::delete_irq(kirq); } Irq_session_component::Irq_session_component(Cap_session * const cap_session, Range_allocator * const irq_alloc, const char * const args) -: - _irq_alloc(irq_alloc) +: _irq_alloc(irq_alloc) { + using namespace Kernel; + /* check arguments */ bool shared = Arg_string::find_arg(args, "irq_shared").bool_value(false); if (shared) { PERR("shared interrupts not supported"); throw Root::Invalid_args(); } + /* allocate interrupt */ long irq_nr = Arg_string::find_arg(args, "irq_number").long_value(-1); bool error = irq_nr < 0 || !_irq_alloc; @@ -70,8 +76,10 @@ Irq_session_component::Irq_session_component(Cap_session * const cap_session PERR("unavailable interrupt requested"); throw Root::Invalid_args(); } + /* make interrupt accessible */ - _irq_number = (unsigned)plat_irq_nr; - _signal = Kernel::User_irq::signal(plat_irq_nr); + new_irq((addr_t)&_kernel_object, plat_irq_nr); + User_irq * kirq = reinterpret_cast(&_kernel_object); + _signal = { kirq->receiver_id(), kirq->context_id() }; _cap = Irq_session_capability(irq_session_ep()->manage(this)); } diff --git a/repos/base-hw/src/core/kernel/kernel.cc b/repos/base-hw/src/core/kernel/kernel.cc index 705c93090..05338f4b6 100644 --- a/repos/base-hw/src/core/kernel/kernel.cc +++ b/repos/base-hw/src/core/kernel/kernel.cc @@ -141,18 +141,6 @@ namespace Kernel return unmanaged_singleton(table, slab); } - /** - * Return wether interrupt 'irq' is private to the kernel - */ - bool private_interrupt(unsigned const irq) - { - for (unsigned i = 0; i < NR_OF_CPUS; i++) - if (irq == Timer::interrupt_id(i)) return true; - if (irq == Pic::IPI) return true; - return false; - } - - /** * Get attributes of the mode transition region in every PD */ @@ -260,12 +248,6 @@ void init_kernel_mp_primary() t.init(cpu_pool()->primary_cpu(), core_pd(), (Native_utcb*)Genode::UTCB_MAIN_THREAD, 1); - /* initialize user interrupt objects */ - static Genode::uint8_t _irqs[Kernel::Pic::NR_OF_IRQ * sizeof(User_irq)]; - for (unsigned i = 0; i < Kernel::Pic::NR_OF_IRQ; i++) { - if (private_interrupt(i)) { continue; } - new (&_irqs[i * sizeof(User_irq)]) User_irq(i); - } /* kernel initialization finished */ Genode::printf("kernel initialized\n"); test(); diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc index 765076702..cb0dcc3a1 100644 --- a/repos/base-hw/src/core/kernel/thread.cc +++ b/repos/base-hw/src/core/kernel/thread.cc @@ -688,6 +688,14 @@ void Thread::_call_delete_signal_receiver() { reinterpret_cast(user_arg_1())->~Signal_receiver(); } +void Thread::_call_new_irq() { + new ((void *)user_arg_1()) User_irq(user_arg_2()); } + + +void Thread::_call_delete_irq() { + reinterpret_cast(user_arg_1())->~User_irq(); } + + int Thread::_read_reg(addr_t const id, addr_t & value) const { addr_t Thread::* const reg = _reg(id); @@ -762,6 +770,8 @@ void Thread::_call() case call_id_run_vm(): _call_run_vm(); return; case call_id_pause_vm(): _call_pause_vm(); return; case call_id_pause_thread(): _call_pause_thread(); return; + case call_id_new_irq(): _call_new_irq(); return; + case call_id_delete_irq(): _call_delete_irq(); return; default: PWRN("%s -> %s: unknown kernel call", pd_label(), label()); _stop(); diff --git a/repos/base-hw/src/core/platform.cc b/repos/base-hw/src/core/platform.cc index cff6c34a8..2aeabb065 100644 --- a/repos/base-hw/src/core/platform.cc +++ b/repos/base-hw/src/core/platform.cc @@ -150,9 +150,12 @@ Platform::Platform() _init_io_port_alloc(); - /* make interrupts available to the interrupt allocator */ - for (unsigned i = 0; i < Kernel::Pic::NR_OF_IRQ; i++) + /* make all non-kernel interrupts available to the interrupt allocator */ + for (unsigned i = 0; i < Kernel::Pic::NR_OF_IRQ; i++) { + if (i == Timer::interrupt_id(i) || i == Pic::IPI) + continue; _irq_alloc.add_range(i, 1); + } /* * Use byte granuarity for MMIO regions because on some platforms, devices diff --git a/repos/base-hw/src/core/spec/arm_gic/pic.cc b/repos/base-hw/src/core/spec/arm_gic/pic.cc index 3a188151d..28033fff0 100644 --- a/repos/base-hw/src/core/spec/arm_gic/pic.cc +++ b/repos/base-hw/src/core/spec/arm_gic/pic.cc @@ -25,6 +25,7 @@ void Pic::_init() for (unsigned i = min_spi; i <= _max_irq; i++) { _distr.write(0, i); _distr.write(0, i); + _distr.write(1, i); } /* enable device */ _distr.write(1); diff --git a/repos/base-hw/src/core/spec/arndale/pic.cc b/repos/base-hw/src/core/spec/arndale/pic.cc index 55c6e6913..9cc73c695 100644 --- a/repos/base-hw/src/core/spec/arndale/pic.cc +++ b/repos/base-hw/src/core/spec/arndale/pic.cc @@ -27,6 +27,7 @@ void Pic::_init() _distr.write(1, i); _distr.write(0, i); _distr.write(0, i); + _distr.write(1, i); } /* enable device */ Distr::Ctlr::access_t v = 0;