diff --git a/repos/base-hw/src/core/include/kernel/cpu.h b/repos/base-hw/src/core/include/kernel/cpu.h index f660d50ab..5a6945814 100644 --- a/repos/base-hw/src/core/include/kernel/cpu.h +++ b/repos/base-hw/src/core/include/kernel/cpu.h @@ -20,6 +20,7 @@ #include #include #include +#include /* base includes */ #include @@ -232,22 +233,51 @@ class Kernel::Cpu_idle : public Genode::Cpu::User_context, public Cpu_job Cpu_job * helping_sink() { return this; } }; -class Kernel::Cpu : public Genode::Cpu +class Kernel::Cpu : public Genode::Cpu, + public Irq::Pool { private: typedef Cpu_job Job; + /** + * Inter-processor-interrupt object of the cpu + */ + struct Ipi : Irq + { + bool pending = false; + + + /********************* + ** Irq interface ** + *********************/ + + void occurred(); + + /** + * Constructor + * + * \param p interrupt pool this irq shall reside in + */ + Ipi(Irq::Pool &p); + + /** + * Trigger the ipi + * + * \param cpu_id id of the cpu this ipi object is related to + */ + void trigger(unsigned const cpu_id); + }; + unsigned const _id; Cpu_idle _idle; Timer * const _timer; Cpu_scheduler _scheduler; - bool _ip_interrupt_pending; + Ipi _ipi_irq; + Irq _timer_irq; /* timer irq implemented as empty event */ unsigned _quota() const { return _timer->ms_to_tics(cpu_quota_ms); } - unsigned _fill() const { return _timer->ms_to_tics(cpu_fill_ms); } - Job * _scheduled_job() const { - return static_cast(_scheduler.head())->helping_sink(); } + unsigned _fill() const { return _timer->ms_to_tics(cpu_fill_ms); } public: @@ -255,25 +285,29 @@ class Kernel::Cpu : public Genode::Cpu * Construct object for CPU 'id' with scheduling timer 'timer' */ Cpu(unsigned const id, Timer * const timer) - : - _id(id), _idle(this), _timer(timer), - _scheduler(&_idle, _quota(), _fill()), - _ip_interrupt_pending(false) { } - - /** - * Check if IRQ 'i' was due to a scheduling timeout - */ - bool timer_irq(unsigned const i) { return _timer->interrupt_id(_id) == i; } - - /** - * Notice that the IPI of the CPU isn't pending anymore - */ - void ip_interrupt_handled() { _ip_interrupt_pending = false; } + : _id(id), _idle(this), _timer(timer), + _scheduler(&_idle, _quota(), _fill()), + _ipi_irq(*this), + _timer_irq(_timer->interrupt_id(_id), *this) { } /** * Raise the IPI of the CPU */ - void trigger_ip_interrupt(); + void trigger_ip_interrupt() { _ipi_irq.trigger(_id); } + + /** + * Deliver interrupt to the CPU + * + * \param irq_id id of the interrupt that occured + * \returns true if the interrupt belongs to this CPU, otherwise false + */ + bool interrupt(unsigned const irq_id) + { + Irq * const irq = object(irq_id); + if (!irq) return false; + irq->occurred(); + return true; + } /** * Schedule 'job' at this CPU @@ -286,7 +320,7 @@ class Kernel::Cpu : public Genode::Cpu void exception() { /* update old job */ - Job * const old_job = _scheduled_job(); + Job * const old_job = scheduled_job(); old_job->exception(_id); /* update scheduler */ @@ -296,7 +330,7 @@ class Kernel::Cpu : public Genode::Cpu _scheduler.update(quota); /* get new job */ - Job * const new_job = _scheduled_job(); + Job * const new_job = scheduled_job(); quota = _scheduler.head_quota(); assert(quota); _timer->start_one_shot(quota, _id); @@ -314,6 +348,12 @@ class Kernel::Cpu : public Genode::Cpu ** Accessors ** ***************/ + /** + * Returns the currently active job + */ + Job * scheduled_job() const { + return static_cast(_scheduler.head())->helping_sink(); } + unsigned id() const { return _id; } Cpu_scheduler * scheduler() { return &_scheduler; } }; @@ -351,6 +391,11 @@ class Kernel::Cpu_pool */ Cpu * primary_cpu() const { return cpu(Cpu::primary_id()); } + /** + * Return object of current CPU + */ + Cpu * executing_cpu() const { return cpu(Cpu::executing_id()); } + /* * Accessors */ diff --git a/repos/base-hw/src/core/include/kernel/irq.h b/repos/base-hw/src/core/include/kernel/irq.h index 5fd33a433..08939437a 100644 --- a/repos/base-hw/src/core/include/kernel/irq.h +++ b/repos/base-hw/src/core/include/kernel/irq.h @@ -1,6 +1,7 @@ /* * \brief Kernel back-end and core front-end for user interrupts * \author Martin Stein + * \author Stefan Kalkowski * \date 2013-10-28 */ @@ -25,9 +26,14 @@ namespace Kernel { /** - * Kernel back-end of a user interrupt + * Kernel back-end interface of an interrupt */ class Irq; + + /** + * Kernel back-end of a user interrupt + */ + class User_irq; } namespace Genode @@ -38,27 +44,10 @@ namespace Genode class Irq; } -class Kernel::Irq -: - public Object_pool::Item, - public Signal_receiver, - public Signal_context, - public Signal_ack_handler + +class Kernel::Irq : public Object_pool::Item { - 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; - } + protected: /** * Prevent interrupt from occurring @@ -75,6 +64,55 @@ class Kernel::Irq */ unsigned _id() const { return Pool::Item::id(); }; + public: + + using Pool = Object_pool; + + /** + * Constructor + * + * \param irq_id kernel name of the interrupt + */ + Irq(unsigned const irq_id) + : Pool::Item(irq_id) { } + + /** + * Constructor + * + * \param irq_id kernel name of the interrupt + * \param pool pool this interrupt shall belong to + */ + Irq(unsigned const irq_id, Pool &pool) + : Irq(irq_id) { pool.insert(this); } + + /** + * Destructor + * + * By now, there is no use case to destruct interrupts + */ + virtual ~Irq() { PERR("destruction of interrupts not implemented"); } + + /** + * Handle occurence of the interrupt + */ + virtual void occurred() { } +}; + + +class Kernel::User_irq +: + public Kernel::Irq, + public Signal_receiver, + public Signal_context, + public Signal_ack_handler +{ + private: + + /** + * Get map that provides all user interrupts by their kernel names + */ + static Irq::Pool * _pool(); + /** * Get kernel name of the interrupt-signal receiver */ @@ -85,43 +123,6 @@ class Kernel::Irq */ 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("destruction of interrupts not implemented"); - while (1) { } - } - /************************ ** Signal_ack_handler ** @@ -136,14 +137,39 @@ class Kernel::Irq * * \param irq_id kernel name of the interrupt */ - Irq(unsigned const irq_id) - : - Pool::Item(irq_id), - Signal_context(this, 0) + User_irq(unsigned const irq_id) + : Irq(irq_id), Signal_context(this, 0) { - Signal_context::ack_handler(this); _pool()->insert(this); _disable(); + Signal_context::ack_handler(this); + } + + /** + * 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 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; } /** @@ -151,30 +177,8 @@ class Kernel::Irq * * \param irq_id kernel name of targeted interrupt */ - static void occurred(unsigned const irq_id) - { - Irq * const irq = _pool()->object(irq_id); - if (!irq) { - PWRN("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); - } + static User_irq * object(unsigned const irq_id) { + return dynamic_cast(_pool()->object(irq_id)); } }; #endif /* _KERNEL__IRQ_H_ */ diff --git a/repos/base-hw/src/core/include/spec/arm_gic/pic.h b/repos/base-hw/src/core/include/spec/arm_gic/pic.h index a1116abbc..c2bf521fd 100644 --- a/repos/base-hw/src/core/include/spec/arm_gic/pic.h +++ b/repos/base-hw/src/core/include/spec/arm_gic/pic.h @@ -177,12 +177,15 @@ class Genode::Arm_gic_cpu_interface : public Mmio class Genode::Pic { + public: + + enum { IPI = 1 }; + protected: typedef Arm_gic_cpu_interface Cpui; typedef Arm_gic_distributor Distr; - static constexpr unsigned ipi = 1; static constexpr unsigned min_spi = 32; static constexpr unsigned spurious_id = 1023; @@ -260,14 +263,6 @@ class Genode::Pic void mask(unsigned const irq_id) { _distr.write(1, irq_id); } - /** - * Return wether an IRQ is inter-processor IRQ of a CPU - * - * \param irq_id kernel name of the IRQ - */ - bool is_ip_interrupt(unsigned const irq_id) { - return irq_id == ipi; } - /** * Raise inter-processor IRQ of the CPU with kernel name 'cpu_id' */ @@ -275,7 +270,7 @@ class Genode::Pic { typedef Distr::Sgir Sgir; Sgir::access_t sgir = 0; - Sgir::Sgi_int_id::set(sgir, ipi); + Sgir::Sgi_int_id::set(sgir, IPI); Sgir::Cpu_target_list::set(sgir, 1 << cpu_id); _distr.write(sgir); } diff --git a/repos/base-hw/src/core/include/spec/imx53/pic.h b/repos/base-hw/src/core/include/spec/imx53/pic.h index af5ad4352..ff0035ac3 100644 --- a/repos/base-hw/src/core/include/spec/imx53/pic.h +++ b/repos/base-hw/src/core/include/spec/imx53/pic.h @@ -32,7 +32,14 @@ class Genode::Pic : public Mmio { public: - enum { NR_OF_IRQ = 109 }; + enum { + /* + * FIXME: dummy ipi value on non-SMP platform, should be removed + * when SMP is an aspect of CPUs only compiled where necessary + */ + IPI = 0, + NR_OF_IRQ = 109, + }; protected: @@ -146,10 +153,6 @@ class Genode::Pic : public Mmio void mask(unsigned const i) { if (valid(i)) { write(1, i); } } - /** - * Wether an interrupt is inter-processor interrupt of a CPU - */ - bool is_ip_interrupt(unsigned) { return false; } /************* ** Dummies ** diff --git a/repos/base-hw/src/core/include/spec/rpi/pic.h b/repos/base-hw/src/core/include/spec/rpi/pic.h index 2368ce38f..ea17080de 100644 --- a/repos/base-hw/src/core/include/spec/rpi/pic.h +++ b/repos/base-hw/src/core/include/spec/rpi/pic.h @@ -135,7 +135,14 @@ class Genode::Pic : Mmio { public: - enum { NR_OF_IRQ = 64 }; + enum { + /* + * FIXME: dummy ipi value on non-SMP platform, should be removed + * when SMP is an aspect of CPUs only compiled where necessary + */ + IPI = 63, + NR_OF_IRQ = 64, + }; private: diff --git a/repos/base-hw/src/core/irq_session_component.cc b/repos/base-hw/src/core/irq_session_component.cc index ea7d2014c..452308086 100644 --- a/repos/base-hw/src/core/irq_session_component.cc +++ b/repos/base-hw/src/core/irq_session_component.cc @@ -63,6 +63,6 @@ Irq_session_component::Irq_session_component(Cap_session * const cap_session throw Root::Invalid_args(); } /* make interrupt accessible */ - _signal = Irq::signal(irq_number); + _signal = Kernel::User_irq::signal(irq_number); _cap = Irq_session_capability(irq_session_ep()->manage(this)); } diff --git a/repos/base-hw/src/core/kernel/cpu.cc b/repos/base-hw/src/core/kernel/cpu.cc index 32af596bd..f1efe15d8 100644 --- a/repos/base-hw/src/core/kernel/cpu.cc +++ b/repos/base-hw/src/core/kernel/cpu.cc @@ -92,24 +92,19 @@ void Cpu_job::_interrupt(unsigned const cpu_id) { /* determine handling for specific interrupt */ unsigned irq_id; - Pic * const ic = pic(); - if (ic->take_request(irq_id)) { + if (pic()->take_request(irq_id)) - /* check wether the interrupt is a CPU-scheduling timeout */ - if (!_cpu->timer_irq(irq_id)) { + /* is the interrupt a cpu-local one */ + if (!_cpu->interrupt(irq_id)) { - /* check wether the interrupt is our IPI */ - if (ic->is_ip_interrupt(irq_id)) { - - cpu_domain_update_list()->do_each(); - _cpu->ip_interrupt_handled(); - - /* try to inform the user interrupt-handler */ - } else { Irq::occurred(irq_id); } + /* it needs to be a user interrupt */ + User_irq * irq = User_irq::object(irq_id); + if (irq) irq->occurred(); + else PWRN("Unknown interrupt %u", irq_id); } - } + /* end interrupt request at controller */ - ic->finish_request(); + pic()->finish_request(); } @@ -138,15 +133,25 @@ void Cpu::schedule(Job * const job) } -void Cpu::trigger_ip_interrupt() +void Cpu::Ipi::occurred() { - if (!_ip_interrupt_pending) { - pic()->trigger_ip_interrupt(_id); - _ip_interrupt_pending = true; - } + cpu_domain_update_list()->do_each(); + pending = false; } +void Cpu::Ipi::trigger(unsigned const cpu_id) +{ + if (pending) return; + + pic()->trigger_ip_interrupt(cpu_id); + pending = true; +} + + +Cpu::Ipi::Ipi(Irq::Pool &p) : Irq(Pic::IPI, p) { } + + /*********************** ** Cpu_domain_update ** ***********************/ diff --git a/repos/base-hw/src/core/kernel/irq.cc b/repos/base-hw/src/core/kernel/irq.cc index aa29775a6..ff5b8eb07 100644 --- a/repos/base-hw/src/core/kernel/irq.cc +++ b/repos/base-hw/src/core/kernel/irq.cc @@ -22,4 +22,10 @@ namespace Kernel { Pic * pic(); } void Irq::_disable() const { pic()->mask(_id()); } -void Irq::_enable() const { pic()->unmask(_id(), Cpu::executing_id()); } +void Irq::_enable() const { pic()->unmask(_id(), Cpu::executing_id()); } + +Irq::Pool * User_irq::_pool() +{ + static Irq::Pool p; + return &p; +} diff --git a/repos/base-hw/src/core/kernel/kernel.cc b/repos/base-hw/src/core/kernel/kernel.cc index 7fa71c73e..70743bbd4 100644 --- a/repos/base-hw/src/core/kernel/kernel.cc +++ b/repos/base-hw/src/core/kernel/kernel.cc @@ -161,10 +161,10 @@ namespace Kernel */ bool private_interrupt(unsigned const irq) { - for (unsigned i = 0; i < NR_OF_CPUS; i++) { - if (irq == Timer::interrupt_id(i)) { return 1; } - } - return 0; + 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; } } @@ -261,11 +261,11 @@ void init_kernel_mp_primary() t.sp = (addr_t)s + STACK_SIZE; t.init(cpu_pool()->primary_cpu(), core_pd(), &utcb, 1); - /* initialize interrupt objects */ - static Genode::uint8_t _irqs[Pic::NR_OF_IRQ * sizeof(Irq)]; + /* initialize user interrupt objects */ + static Genode::uint8_t _irqs[Pic::NR_OF_IRQ * sizeof(User_irq)]; for (unsigned i = 0; i < Pic::NR_OF_IRQ; i++) { if (private_interrupt(i)) { continue; } - new (&_irqs[i * sizeof(Irq)]) Irq(i); + new (&_irqs[i * sizeof(User_irq)]) User_irq(i); } /* kernel initialization finished */ Genode::printf("kernel initialized\n");