/* * \brief Class for kernel data that is needed to manage a specific CPU * \author Martin Stein * \author Stefan Kalkowski * \date 2014-01-14 */ /* * Copyright (C) 2014-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ #ifndef _CORE__KERNEL__CPU_H_ #define _CORE__KERNEL__CPU_H_ #include /* core includes */ #include #include "cpu_context.h" #include "irq.h" #include "inter_processor_work.h" #include "thread.h" namespace Kernel { /** * Class for kernel data that is needed to manage a specific CPU */ class Cpu; /** * Provides a CPU object for every available CPU */ class Cpu_pool; /** * Return singleton of CPU pool */ Cpu_pool &cpu_pool(); } /* * The 'Cpu' class violates the "Effective C++" practices because it publicly * inherits the 'Genode::Cpu' base class, which does not have a virtual * destructor. Since 'Cpu' implements the 'Timeout' interface, however, it has * a vtable. * * Adding a virtual destructor in the base class would be unnatural as the base * class hierarchy does not represent an abstract interface. * * Inheriting the 'Genode::Cpu' class privately is not an option because the * user of 'Cpu' class expects architecture-specific register definitions to be * provided by 'Cpu'. Hence, all those architecture- specific definitions would * end up as 'using' clauses in the generic class. * * XXX Remove the disabled warning, e.g., by one of the following approaches: * * * Prevent 'Cpu' to have virtual methods by making 'Timeout' a member instead * of a base class. * * * Change the class hierarchy behind 'Genode::Cpu' such that * architecture-specific bits do no longer need to implicitly become part * of the public interface of 'Cpu'. For example, register-definition types * could all be embedded in an 'Arch_regs' type, which the 'Cpu' class could * publicly provide via a 'typedef Genode::Cpu::Arch_regs Arch_regs'. * Then, the 'Genode::Cpu' could be inherited privately. */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout { private: typedef Cpu_job Job; /** * Inter-processor-interrupt object of the cpu */ struct Ipi : Irq { Cpu & cpu; bool pending { false }; /** * Constructor * * \param cpu cpu this IPI belongs to */ Ipi(Cpu & cpu); /********************* ** Irq interface ** *********************/ void occurred() override; }; friend void Ipi::occurred(void); struct Idle_thread : Kernel::Thread { /** * Construct idle context for CPU 'cpu' */ Idle_thread(Cpu &cpu); }; unsigned const _id; Board::Pic &_pic; Timer _timer; Cpu_scheduler _scheduler; Idle_thread _idle; Ipi _ipi_irq; Inter_processor_work_list &_global_work_list; Inter_processor_work_list _local_work_list {}; void _arch_init(); unsigned _quota() const { return _timer.us_to_ticks(cpu_quota_us); } unsigned _fill() const { return _timer.us_to_ticks(cpu_fill_us); } public: enum { KERNEL_STACK_SIZE = 16 * 1024 * sizeof(Genode::addr_t) }; /** * Construct object for CPU 'id' */ Cpu(unsigned const id, Board::Pic & pic, Inter_processor_work_list & global_work_list); static inline unsigned primary_id() { return 0; } /** * Raise the IPI of the CPU */ void trigger_ip_interrupt(); /** * 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); /** * Schedule 'job' at this CPU */ void schedule(Job * const job); /** * Return the job that should be executed at next */ Cpu_job& schedule(); Board::Pic & pic() { return _pic; } Timer & timer() { return _timer; } addr_t stack_start(); /** * 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; } Irq::Pool &irq_pool() { return *this; } Inter_processor_work_list & work_list() { return _local_work_list; } }; /* * See the comment above the 'Cpu' class definition. */ #pragma GCC diagnostic pop class Kernel::Cpu_pool { private: Board::Pic _pic {}; Inter_processor_work_list _global_work_list {}; unsigned _count; unsigned _initialized { _count }; Genode::Constructible _cpus[NR_OF_CPUS]; public: Cpu_pool(); bool initialize(); /** * Return object of CPU 'id' */ Cpu & cpu(unsigned const id); /** * Return object of primary CPU */ Cpu & primary_cpu() { return cpu(Cpu::primary_id()); } /** * Return object of current CPU */ Cpu & executing_cpu() { return cpu(Cpu::executing_id()); } template void for_each_cpu(FUNC const &func) { for (unsigned i = 0; i < _count; i++) func(cpu(i)); } Inter_processor_work_list & work_list() { return _global_work_list; } }; #endif /* _CORE__KERNEL__CPU_H_ */