diff --git a/repos/base-hw/lib/mk/core-hw.inc b/repos/base-hw/lib/mk/core-hw.inc index e2540570e..760d50877 100644 --- a/repos/base-hw/lib/mk/core-hw.inc +++ b/repos/base-hw/lib/mk/core-hw.inc @@ -55,7 +55,7 @@ SRC_CC += kernel/ipc_node.cc SRC_CC += kernel/irq.cc SRC_CC += kernel/pd.cc SRC_CC += kernel/cpu.cc -SRC_CC += kernel/clock.cc +SRC_CC += kernel/timer.cc SRC_CC += kernel/object.cc SRC_CC += init_main_thread.cc SRC_CC += capability.cc diff --git a/repos/base-hw/src/core/kernel/cpu.cc b/repos/base-hw/src/core/kernel/cpu.cc index b937a3738..f66bfd43b 100644 --- a/repos/base-hw/src/core/kernel/cpu.cc +++ b/repos/base-hw/src/core/kernel/cpu.cc @@ -19,7 +19,6 @@ #include #include #include -#include #include /* base-internal includes */ @@ -133,14 +132,14 @@ void Cpu_idle::_main() { while (1) { Genode::Cpu::wait_for_interrupt(); } } *********/ void Cpu::set_timeout(Timeout * const timeout, time_t const duration_us) { - _clock.set_timeout(timeout, _clock.us_to_tics(duration_us)); } + _timer.set_timeout(timeout, _timer.us_to_ticks(duration_us)); } time_t Cpu::timeout_age_us(Timeout const * const timeout) const { - return _clock.timeout_age_us(timeout); } + return _timer.timeout_age_us(timeout); } -time_t Cpu::timeout_max_us() const { return _clock.timeout_max_us(); } +time_t Cpu::timeout_max_us() const { return _timer.timeout_max_us(); } void Cpu::schedule(Job * const job) @@ -162,19 +161,19 @@ bool Cpu::interrupt(unsigned const irq_id) Cpu_job & Cpu::schedule() { /* update scheduler */ - time_t quota = _clock.update_time(); + time_t quota = _timer.update_time(); Job & old_job = scheduled_job(); old_job.exception(id()); - _clock.process_timeouts(); + _timer.process_timeouts(); _scheduler.update(quota); /* get new job */ Job & new_job = scheduled_job(); quota = _scheduler.head_quota(); - _clock.set_timeout(this, quota); + _timer.set_timeout(this, quota); - _clock.schedule_timeout(); + _timer.schedule_timeout(); /* switch to new job */ switch_to(new_job); @@ -184,11 +183,11 @@ Cpu_job & Cpu::schedule() } -Cpu::Cpu(unsigned const id, Timer * const timer) +Cpu::Cpu(unsigned const id) : - _id(id), _clock(_id, timer), _idle(this), + _id(id), _timer(_id), _idle(this), _scheduler(&_idle, _quota(), _fill()), - _ipi_irq(*this), _timer_irq(timer->interrupt_id(_id), *this) + _ipi_irq(*this), _timer_irq(_timer.interrupt_id(), *this) { } @@ -206,27 +205,8 @@ Cpu * Cpu_pool::cpu(unsigned const id) const Cpu_pool::Cpu_pool() { - /* - * The timer frequency should allow a good accuracy on the smallest - * timeout syscall value (1 us). - */ - assert(_timer.tics_to_us(1) < 1 || - _timer.tics_to_us(_timer.max_value()) == _timer.max_value()); - - /* - * The maximum measurable timeout is also the maximum age of a timeout - * installed by the timeout syscall. The timeout-age syscall returns a - * bogus value for older timeouts. A user that awoke from waiting for a - * timeout might not be schedulable in the same super period anymore. - * However, if the user can't manage to read the timeout age during the - * next super period, it's a bad configuration or the users fault. That - * said, the maximum timeout should be at least two times the super - * period). - */ - assert(_timer.tics_to_us(_timer.max_value()) > 2 * cpu_quota_us); - for (unsigned id = 0; id < NR_OF_CPUS; id++) { - new (_cpus[id]) Cpu(id, &_timer); } + new (_cpus[id]) Cpu(id); } } diff --git a/repos/base-hw/src/core/kernel/cpu.h b/repos/base-hw/src/core/kernel/cpu.h index d9587573e..e81f78c63 100644 --- a/repos/base-hw/src/core/kernel/cpu.h +++ b/repos/base-hw/src/core/kernel/cpu.h @@ -16,7 +16,7 @@ #define _CORE__KERNEL__CPU_H_ /* core includes */ -#include +#include #include #include #include @@ -269,21 +269,21 @@ class Kernel::Cpu : public Genode::Cpu, public Irq::Pool, private Timeout }; unsigned const _id; - Clock _clock; + Timer _timer; Cpu_idle _idle; Cpu_scheduler _scheduler; Ipi _ipi_irq; - Irq _timer_irq; /* timer irq implemented as empty event */ + Irq _timer_irq; /* timer IRQ implemented as empty event */ - unsigned _quota() const { return _clock.us_to_tics(cpu_quota_us); } - unsigned _fill() const { return _clock.us_to_tics(cpu_fill_us); } + unsigned _quota() const { return _timer.us_to_ticks(cpu_quota_us); } + unsigned _fill() const { return _timer.us_to_ticks(cpu_fill_us); } public: /** - * Construct object for CPU 'id' with scheduling timer 'timer' + * Construct object for CPU 'id' */ - Cpu(unsigned const id, Timer * const timer); + Cpu(unsigned const id); /** * Initialize primary cpu object @@ -335,14 +335,16 @@ class Kernel::Cpu : public Genode::Cpu, public Irq::Pool, private Timeout unsigned id() const { return _id; } Cpu_scheduler * scheduler() { return &_scheduler; } + + time_t us_to_ticks(time_t const us) const { return _timer.us_to_ticks(us); }; + + unsigned timer_interrupt_id() const { return _timer.interrupt_id(); } }; class Kernel::Cpu_pool { private: - Timer _timer; - /* * Align to machine word size, otherwise load/stores might fail on some * platforms. @@ -369,11 +371,13 @@ class Kernel::Cpu_pool */ Cpu * executing_cpu() const { return cpu(Cpu::executing_id()); } - /* - * Accessors - */ - - Timer * timer() { return &_timer; } + template + void for_each_cpu(FUNC const &func) const + { + for (unsigned i = 0; i < sizeof(_cpus)/sizeof(_cpus[i]); i++) { + func(*cpu(i)); + } + } }; #endif /* _CORE__KERNEL__CPU_H_ */ diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc index edb9b51aa..1fde96c25 100644 --- a/repos/base-hw/src/core/kernel/thread.cc +++ b/repos/base-hw/src/core/kernel/thread.cc @@ -153,8 +153,8 @@ size_t Thread::_core_to_kernel_quota(size_t const quota) const { using Genode::Cpu_session; using Genode::sizet_arithm_t; - size_t const tics = cpu_pool()->timer()->us_to_tics(Kernel::cpu_quota_us); - return Cpu_session::quota_lim_downscale(quota, tics); + size_t const ticks = _cpu->us_to_ticks(Kernel::cpu_quota_us); + return Cpu_session::quota_lim_downscale(quota, ticks); } diff --git a/repos/base-hw/src/core/kernel/thread.h b/repos/base-hw/src/core/kernel/thread.h index f0d5b46c3..0a9ab5701 100644 --- a/repos/base-hw/src/core/kernel/thread.h +++ b/repos/base-hw/src/core/kernel/thread.h @@ -124,7 +124,7 @@ class Kernel::Thread void _call(); /** - * Return amount of timer tics that 'quota' is worth + * Return amount of timer ticks that 'quota' is worth */ size_t _core_to_kernel_quota(size_t const quota) const; diff --git a/repos/base-hw/src/core/kernel/clock.cc b/repos/base-hw/src/core/kernel/timer.cc similarity index 66% rename from repos/base-hw/src/core/kernel/clock.cc rename to repos/base-hw/src/core/kernel/timer.cc index c55845b13..2cba311d1 100644 --- a/repos/base-hw/src/core/kernel/clock.cc +++ b/repos/base-hw/src/core/kernel/timer.cc @@ -1,5 +1,5 @@ /* - * \brief A clock manages a continuous time and timeouts on it + * \brief A timer manages a continuous time and timeouts on it * \author Martin Stein * \date 2016-03-23 */ @@ -12,38 +12,33 @@ */ /* Core includes */ -#include +#include +#include #include using namespace Kernel; -time_t Clock::us_to_tics(time_t const us) const -{ - return _timer->us_to_tics(us); -} - - -time_t Clock::timeout_age_us(Timeout const * const timeout) const +time_t Timer::timeout_age_us(Timeout const * const timeout) const { time_t const age = (time_t)_time - timeout->_start; - return _timer->tics_to_us(age); + return _ticks_to_us(age); } -time_t Clock::timeout_max_us() const +time_t Timer::timeout_max_us() const { - return _timer->tics_to_us(_timer->max_value()); + return _ticks_to_us(_max_value()); } -bool Clock::_time_overflow(time_t const duration) const +bool Timer::_time_overflow(time_t const duration) const { return duration > ~(time_t)0 - _time; } -void Clock::set_timeout(Timeout * const timeout, time_t const duration) +void Timer::set_timeout(Timeout * const timeout, time_t const duration) { /* * Remove timeout if it is already in use. Timeouts may get overridden as @@ -73,7 +68,7 @@ void Clock::set_timeout(Timeout * const timeout, time_t const duration) } -void Clock::schedule_timeout() +void Timer::schedule_timeout() { /* get the timeout with the nearest end time */ Timeout * timeout = _timeout_list[_time_period].first(); @@ -84,15 +79,15 @@ void Clock::schedule_timeout() /* install timeout at timer hardware */ time_t const duration = (time_t)timeout->_end - _time; _last_timeout_duration = duration; - _timer->start_one_shot(duration, _cpu_id); + _start_one_shot(duration); } -time_t Clock::update_time() +time_t Timer::update_time() { /* determine how much time has passed */ time_t const old_value = _last_timeout_duration; - time_t const new_value = _timer->value(_cpu_id); + time_t const new_value = _value(); time_t const duration = old_value > new_value ? old_value - new_value : 1; /* is this the end of the current period? */ @@ -117,7 +112,7 @@ time_t Clock::update_time() } -void Clock::process_timeouts() +void Timer::process_timeouts() { /* * Walk through timeouts until the first whose end time is in the future. @@ -136,6 +131,23 @@ void Clock::process_timeouts() } -Clock::Clock(unsigned const cpu_id, Timer * const timer) -: - _cpu_id(cpu_id), _timer(timer) { } +Timer::Timer(unsigned cpu_id) : _cpu_id(cpu_id), _driver(cpu_id) +{ + /* + * The timer frequency should allow a good accuracy on the smallest + * timeout syscall value (1 us). + */ + assert(_ticks_to_us(1) < 1 || _ticks_to_us(_max_value()) == _max_value()); + + /* + * The maximum measurable timeout is also the maximum age of a timeout + * installed by the timeout syscall. The timeout-age syscall returns a + * bogus value for older timeouts. A user that awoke from waiting for a + * timeout might not be schedulable in the same super period anymore. + * However, if the user can't manage to read the timeout age during the + * next super period, it's a bad configuration or the users fault. That + * said, the maximum timeout should be at least two times the super + * period). + */ + assert(_ticks_to_us(_max_value()) > 2 * cpu_quota_us); +} diff --git a/repos/base-hw/src/core/kernel/clock.h b/repos/base-hw/src/core/kernel/timer.h similarity index 60% rename from repos/base-hw/src/core/kernel/clock.h rename to repos/base-hw/src/core/kernel/timer.h index bc0efc035..d3c0e45c8 100644 --- a/repos/base-hw/src/core/kernel/clock.h +++ b/repos/base-hw/src/core/kernel/timer.h @@ -1,5 +1,5 @@ /* - * \brief A clock manages a continuous time and timeouts on it + * \brief A timer manages a continuous time and timeouts on it * \author Martin Stein * \date 2016-03-23 */ @@ -11,8 +11,8 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _CORE__KERNEL__CLOCK_H_ -#define _CORE__KERNEL__CLOCK_H_ +#ifndef _CORE__KERNEL__TIMER_H_ +#define _CORE__KERNEL__TIMER_H_ /* base-hw includes */ #include @@ -21,12 +21,12 @@ #include /* Core includes */ -#include +#include namespace Kernel { class Timeout; - class Clock; + class Timer; } /** @@ -34,7 +34,7 @@ namespace Kernel */ class Kernel::Timeout : public Genode::List::Element { - friend class Clock; + friend class Timer; private: @@ -54,14 +54,16 @@ class Kernel::Timeout : public Genode::List::Element }; /** - * A clock manages a continuous time and timeouts on it + * A timer manages a continuous time and timeouts on it */ -class Kernel::Clock +class Kernel::Timer { private: + using Driver = Timer_driver; + unsigned const _cpu_id; - Timer * const _timer; + Driver _driver; time_t _time = 0; bool _time_period = false; Genode::List _timeout_list[2]; @@ -69,39 +71,34 @@ class Kernel::Clock bool _time_overflow(time_t const duration) const; + void _start_one_shot(time_t const ticks); + + time_t _ticks_to_us(time_t const ticks) const; + + time_t _value(); + + time_t _max_value() const; + public: - Clock(unsigned const cpu_id, Timer * const timer); + Timer(unsigned cpu_id); - /** - * Set-up timer according to the current timeout schedule - */ void schedule_timeout(); - /** - * Update time and work off expired timeouts - * - * \return time that passed since the last scheduling - */ time_t update_time(); void process_timeouts(); - /** - * Set-up 'timeout' to trigger at time + 'duration' - */ void set_timeout(Timeout * const timeout, time_t const duration); - /** - * Return native time value that equals the given microseconds 'us' - */ - time_t us_to_tics(time_t const us) const; + time_t us_to_ticks(time_t const us) const; - /** - * Return microseconds that passed since the last set-up of 'timeout' - */ time_t timeout_age_us(Timeout const * const timeout) const; time_t timeout_max_us() const; + + unsigned interrupt_id() const; + + static void init_cpu_local(); }; -#endif /* _CORE__KERNEL__CLOCK_H_ */ +#endif /* _CORE__KERNEL__TIMER_H_ */ diff --git a/repos/base-hw/src/core/platform.cc b/repos/base-hw/src/core/platform.cc index 63d687755..f3bd03717 100644 --- a/repos/base-hw/src/core/platform.cc +++ b/repos/base-hw/src/core/platform.cc @@ -27,6 +27,7 @@ #include #include #include +#include /* base-internal includes */ #include @@ -89,6 +90,8 @@ Platform::Platform() _io_port_alloc(core_mem_alloc()), _irq_alloc(core_mem_alloc()) { + struct Kernel_resource : Exception { }; + _core_mem_alloc.virt_alloc()->add_range(VIRT_ADDR_SPACE_START, VIRT_ADDR_SPACE_SIZE); _core_virt_regions().for_each([this] (Hw::Memory_region const & r) { @@ -102,8 +105,18 @@ Platform::Platform() /* 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) + bool kernel_resource = false; + Kernel::cpu_pool()->for_each_cpu([&] (Kernel::Cpu const &cpu) { + if (i == cpu.timer_interrupt_id()) { + kernel_resource = true; + } + }); + if (i == Pic::IPI) { + kernel_resource = true; + } + if (kernel_resource) { continue; + } _irq_alloc.add_range(i, 1); } diff --git a/repos/base-hw/src/core/spec/arm/kernel/cpu.cc b/repos/base-hw/src/core/spec/arm/kernel/cpu.cc index 807c9267c..590448df8 100644 --- a/repos/base-hw/src/core/spec/arm/kernel/cpu.cc +++ b/repos/base-hw/src/core/spec/arm/kernel/cpu.cc @@ -24,7 +24,7 @@ void Kernel::Cpu::init(Kernel::Pic &pic) perf_counter()->enable(); /* enable timer interrupt */ - pic.unmask(Timer::interrupt_id(id()), id()); + pic.unmask(_timer.interrupt_id(), id()); } diff --git a/repos/base-hw/src/core/spec/arndale/platform_services.cc b/repos/base-hw/src/core/spec/arndale/platform_services.cc index e7782f4c6..3c310adc3 100644 --- a/repos/base-hw/src/core/spec/arndale/platform_services.cc +++ b/repos/base-hw/src/core/spec/arndale/platform_services.cc @@ -21,6 +21,7 @@ #include /* for 'Core_service' type */ #include #include +#include extern Genode::addr_t _vt_host_context_ptr; extern Genode::addr_t _vt_host_entry; diff --git a/repos/base-hw/src/core/spec/cortex_a15/kernel/cpu.cc b/repos/base-hw/src/core/spec/cortex_a15/kernel/cpu.cc index 3c38363b7..ea33314ae 100644 --- a/repos/base-hw/src/core/spec/cortex_a15/kernel/cpu.cc +++ b/repos/base-hw/src/core/spec/cortex_a15/kernel/cpu.cc @@ -38,6 +38,6 @@ void Kernel::Cpu::init(Kernel::Pic &pic/*, Kernel::Pd & core_pd, Genode::Board & perf_counter()->enable(); /* enable timer interrupt */ - pic.unmask(Timer::interrupt_id(id()), id()); + pic.unmask(_timer.interrupt_id(), id()); } } diff --git a/repos/base-hw/src/core/spec/cortex_a9/kernel/cpu.cc b/repos/base-hw/src/core/spec/cortex_a9/kernel/cpu.cc index c436f9f49..11662048c 100644 --- a/repos/base-hw/src/core/spec/cortex_a9/kernel/cpu.cc +++ b/repos/base-hw/src/core/spec/cortex_a9/kernel/cpu.cc @@ -39,6 +39,6 @@ void Kernel::Cpu::init(Kernel::Pic &pic) perf_counter()->enable(); /* enable timer interrupt */ - pic.unmask(Timer::interrupt_id(id()), id()); + pic.unmask(_timer.interrupt_id(), id()); } } diff --git a/repos/base-hw/src/core/spec/cortex_a9/timer.cc b/repos/base-hw/src/core/spec/cortex_a9/timer.cc index 77dc4df14..4a20750f1 100644 --- a/repos/base-hw/src/core/spec/cortex_a9/timer.cc +++ b/repos/base-hw/src/core/spec/cortex_a9/timer.cc @@ -1,6 +1,7 @@ /* * \brief Timer implementation specific to Cortex A9 * \author Stefan Kalkowski + * \author Martin Stein * \date 2016-01-07 */ @@ -11,32 +12,76 @@ * under the terms of the GNU Affero General Public License version 3. */ +/* core includes */ +#include #include -#include -using Genode::Timer; -using Genode::Mmio; -using Genode::Platform; +using namespace Genode; +using namespace Kernel; -Timer::Timer() + +Timer_driver::Timer_driver(unsigned) : Mmio(Platform::mmio_to_virt(Board::Cpu_mmio::PRIVATE_TIMER_MMIO_BASE)) { write(0); } -void Timer::start_one_shot(time_t const tics, unsigned const) +void Timer::_start_one_shot(time_t const ticks) { enum { PRESCALER = Board::CORTEX_A9_PRIVATE_TIMER_DIV - 1 }; /* reset timer */ - write(1); - Control::access_t control = 0; - Control::Irq_enable::set(control, 1); - Control::Prescaler::set(control, PRESCALER); - write(control); + _driver.write(1); + Driver::Control::access_t control = 0; + Driver::Control::Irq_enable::set(control, 1); + Driver::Control::Prescaler::set(control, PRESCALER); + _driver.write(control); /* load timer and start decrementing */ - write(tics); - write(1); + _driver.write(ticks); + _driver.write(1); } + + +time_t Timer::_ticks_to_us(time_t const ticks) const +{ + /* + * If we would do the translation with one division and + * multiplication over the whole argument, we would loose + * microseconds granularity although the timer frequency would + * allow for such granularity. Thus, we treat the most significant + * half and the least significant half of the argument separate. + * Each half is shifted to the best bit position for the + * translation, then translated, and then shifted back. + */ + static_assert(Driver::TICS_PER_MS >= 1000, "Bad TICS_PER_MS value"); + enum { + HALF_WIDTH = (sizeof(time_t) << 2), + MSB_MASK = ~0UL << HALF_WIDTH, + LSB_MASK = ~0UL >> HALF_WIDTH, + MSB_RSHIFT = 10, + LSB_LSHIFT = HALF_WIDTH - MSB_RSHIFT, + }; + time_t const msb = (((ticks >> MSB_RSHIFT) + * 1000) / Driver::TICS_PER_MS) << MSB_RSHIFT; + time_t const lsb = ((((ticks & LSB_MASK) << LSB_LSHIFT) + * 1000) / Driver::TICS_PER_MS) >> LSB_LSHIFT; + return (msb & MSB_MASK) | lsb; +} + + +unsigned Timer::interrupt_id() const { + return Board::Cpu_mmio::PRIVATE_TIMER_IRQ; } + + +time_t Timer::us_to_ticks(time_t const us) const { + return (us / 1000) * Driver::TICS_PER_MS; } + + +time_t Timer::_value() { + return _driver.read(); } + + +time_t Timer::_max_value() const { + return (Driver::Load::access_t)~0; } diff --git a/repos/base-hw/src/core/spec/cortex_a9/timer.h b/repos/base-hw/src/core/spec/cortex_a9/timer.h deleted file mode 100644 index f1dce34b5..000000000 --- a/repos/base-hw/src/core/spec/cortex_a9/timer.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * \brief Timer driver for core - * \author Martin stein - * \date 2011-12-13 - */ - -/* - * Copyright (C) 2011-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__SPEC__CORTEX_A9__TIMER_H_ -#define _CORE__SPEC__CORTEX_A9__TIMER_H_ - -/* base-hw includes */ -#include - -/* Genode includes */ -#include - -/* core includes */ -#include - -namespace Genode { class Timer; } - -/** - * Timer driver for core - */ -class Genode::Timer : public Mmio -{ - private: - - using time_t = Kernel::time_t; - - enum { - TICS_PER_MS = - Board::CORTEX_A9_PRIVATE_TIMER_CLK / - Board::CORTEX_A9_PRIVATE_TIMER_DIV / 1000 - }; - - /** - * Load value register - */ - struct Load : Register<0x0, 32> { }; - - /** - * Counter value register - */ - struct Counter : Register<0x4, 32> { }; - - /** - * Timer control register - */ - struct Control : Register<0x8, 32> - { - struct Timer_enable : Bitfield<0,1> { }; /* enable counting */ - struct Irq_enable : Bitfield<2,1> { }; /* unmask interrupt */ - struct Prescaler : Bitfield<8,8> { }; - }; - - /** - * Timer interrupt status register - */ - struct Interrupt_status : Register<0xc, 32> - { - struct Event : Bitfield<0,1> { }; /* if counter hit zero */ - }; - - public: - - Timer(); - - /** - * Return kernel name of timer interrupt - */ - static unsigned interrupt_id(unsigned const) { - return Board::Cpu_mmio::PRIVATE_TIMER_IRQ; } - - /** - * Start single timeout run - * - * \param tics delay of timer interrupt - */ - void start_one_shot(time_t const tics, unsigned const); - - time_t tics_to_us(time_t const tics) const - { - /* - * If we would do the translation with one division and - * multiplication over the whole argument, we would loose - * microseconds granularity although the timer frequency would - * allow for such granularity. Thus, we treat the most significant - * half and the least significant half of the argument separate. - * Each half is shifted to the best bit position for the - * translation, then translated, and then shifted back. - */ - static_assert(TICS_PER_MS >= 1000, "Bad TICS_PER_MS value"); - enum { - TICS_WIDTH = sizeof(time_t) * 8, - TICS_HALF_WIDTH = TICS_WIDTH / 2, - - TICS_MSB_MASK = ~0UL << TICS_HALF_WIDTH, - TICS_LSB_MASK = ~0UL >> TICS_HALF_WIDTH, - - TICS_MSB_RSHIFT = 10, - TICS_LSB_LSHIFT = TICS_HALF_WIDTH - TICS_MSB_RSHIFT, - }; - time_t const tics_msb = (tics & TICS_MSB_MASK) >> TICS_MSB_RSHIFT; - time_t const tics_lsb = (tics & TICS_LSB_MASK) << TICS_LSB_LSHIFT; - - time_t const us_msb = ((tics_msb * 1000) / TICS_PER_MS) << TICS_MSB_RSHIFT; - time_t const us_lsb = ((tics_lsb * 1000) / TICS_PER_MS) >> TICS_LSB_LSHIFT; - - return us_msb | us_lsb; - } - - time_t us_to_tics(time_t const us) const { - return (us / 1000) * TICS_PER_MS; } - - /** - * Return current native timer value - */ - time_t value(unsigned const) { return read(); } - - time_t max_value() { return (Load::access_t)~0; } -}; - -namespace Kernel { using Genode::Timer; } - -#endif /* _CORE__SPEC__CORTEX_A9__TIMER_H_ */ diff --git a/repos/base-hw/src/core/spec/cortex_a9/timer_driver.h b/repos/base-hw/src/core/spec/cortex_a9/timer_driver.h new file mode 100644 index 000000000..99f341a0d --- /dev/null +++ b/repos/base-hw/src/core/spec/cortex_a9/timer_driver.h @@ -0,0 +1,67 @@ +/* + * \brief Timer implementation specific to Cortex A9 + * \author Martin stein + * \date 2011-12-13 + */ + +/* + * Copyright (C) 2011-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 _TIMER_DRIVER_H_ +#define _TIMER_DRIVER_H_ + +/* Genode includes */ +#include + +/* core includes */ +#include + +namespace Kernel { class Timer_driver; } + +/** + * Timer driver for core + */ +struct Kernel::Timer_driver : Genode::Mmio +{ + enum { + TICS_PER_MS = + Board::CORTEX_A9_PRIVATE_TIMER_CLK / + Board::CORTEX_A9_PRIVATE_TIMER_DIV / 1000 + }; + + /** + * Load value register + */ + struct Load : Register<0x0, 32> { }; + + /** + * Counter value register + */ + struct Counter : Register<0x4, 32> { }; + + /** + * Timer control register + */ + struct Control : Register<0x8, 32> + { + struct Timer_enable : Bitfield<0,1> { }; /* enable counting */ + struct Irq_enable : Bitfield<2,1> { }; /* unmask interrupt */ + struct Prescaler : Bitfield<8,8> { }; + }; + + /** + * Timer interrupt status register + */ + struct Interrupt_status : Register<0xc, 32> + { + struct Event : Bitfield<0,1> { }; /* if counter hit zero */ + }; + + Timer_driver(unsigned); +}; + +#endif /* _TIMER_DRIVER_H_ */ diff --git a/repos/base-hw/src/core/spec/exynos5/timer.cc b/repos/base-hw/src/core/spec/exynos5/timer.cc index aa87e0914..fa0125063 100644 --- a/repos/base-hw/src/core/spec/exynos5/timer.cc +++ b/repos/base-hw/src/core/spec/exynos5/timer.cc @@ -1,5 +1,6 @@ /* * \brief Timer driver for core + * \author Stefan Kalkowski * \author Martin stein * \date 2013-01-10 */ @@ -11,12 +12,30 @@ * under the terms of the GNU Affero General Public License version 3. */ +/* core include */ +#include +#include #include -#include -Genode::Timer::Timer() -: Mmio(Platform::mmio_to_virt(Board::MCT_MMIO_BASE)), - _tics_per_ms(_calc_tics_per_ms(Board::MCT_CLOCK)) +using namespace Genode; +using namespace Kernel; + + +unsigned Timer::interrupt_id() const +{ + switch (_driver.cpu_id) { + case 0: return Board::MCT_IRQ_L0; + case 1: return Board::MCT_IRQ_L1; + default: return 0; + } +} + + +Timer_driver::Timer_driver(unsigned cpu_id) +: + Mmio(Platform::mmio_to_virt(Board::MCT_MMIO_BASE)), + ticks_per_ms(calc_ticks_per_ms(Board::MCT_CLOCK)), + cpu_id(cpu_id) { Mct_cfg::access_t mct_cfg = 0; Mct_cfg::Prescaler::set(mct_cfg, PRESCALER); @@ -25,3 +44,45 @@ Genode::Timer::Timer() write(L0_int_enb::Frceie::bits(1)); write(L1_int_enb::Frceie::bits(1)); } + + +void Timer::_start_one_shot(time_t const ticks) +{ + switch (_driver.cpu_id) { + case 0: + _driver.write(1); + _driver.run_0(0); + _driver.acked_write(ticks); + _driver.run_0(1); + return; + case 1: + _driver.write(1); + _driver.run_1(0); + _driver.acked_write(ticks); + _driver.run_1(1); + return; + default: return; + } +} + + +time_t Timer::_value() +{ + switch (_driver.cpu_id) { + case 0: return _driver.read() ? 0 : _driver.read(); + case 1: return _driver.read() ? 0 : _driver.read(); + default: return 0; + } +} + + +time_t Timer::_ticks_to_us(time_t const ticks) const { + return (ticks / _driver.ticks_per_ms) * 1000; } + + +time_t Timer::us_to_ticks(time_t const us) const { + return (us / 1000) * _driver.ticks_per_ms; } + + +time_t Timer::_max_value() const { + return (Driver::L0_frcnto::access_t)~0; } diff --git a/repos/base-hw/src/core/spec/exynos5/timer.h b/repos/base-hw/src/core/spec/exynos5/timer.h deleted file mode 100644 index 3ad52a734..000000000 --- a/repos/base-hw/src/core/spec/exynos5/timer.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - * \brief Timer driver for core - * \author Martin stein - * \date 2013-01-10 - */ - -/* - * Copyright (C) 2013-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__SPEC__EXYNOS5__TIMER_H_ -#define _CORE__SPEC__EXYNOS5__TIMER_H_ - -/* base-hw includes */ -#include - -/* core include */ -#include - -/* Genode includes */ -#include - -namespace Genode -{ - /** - * Timer driver for core - */ - class Timer; -} - -class Genode::Timer : public Mmio -{ - private: - - using time_t = Kernel::time_t; - - enum { - PRESCALER = 1, - DIV_MUX = 0, - }; - - /** - * MCT configuration - */ - struct Mct_cfg : Register<0x0, 32> - { - struct Prescaler : Bitfield<0, 8> { }; - struct Div_mux : Bitfield<8, 3> { }; - }; - - - /******************* - ** Local timer 0 ** - *******************/ - - /** - * Free running counter buffer - */ - struct L0_frcntb : Register<0x310, 32> { }; - - /** - * Configuration - */ - struct L0_tcon : Register<0x320, 32> - { - struct Frc_start : Bitfield<3, 1> { }; - }; - - /** - * Expired status - */ - struct L0_int_cstat : Register<0x330, 32, true> - { - struct Frcnt : Bitfield<1, 1> { }; - }; - - /** - * Interrupt enable - */ - struct L0_int_enb : Register<0x334, 32> - { - struct Frceie : Bitfield<1, 1> { }; - }; - - /** - * Write status - */ - struct L0_wstat : Register<0x340, 32, true> - { - struct Frcntb : Bitfield<2, 1> { }; - struct Tcon : Bitfield<3, 1> { }; - }; - - struct L0_frcnto : Register<0x314, 32> { }; - - /** - * Start and stop counting - */ - void _run_0(bool const run) - { - _acked_write - (L0_tcon::Frc_start::bits(run)); - } - - - /******************* - ** Local timer 1 ** - *******************/ - - /** - * Free running counter buffer - */ - struct L1_frcntb : Register<0x410, 32> { }; - - /** - * Configuration - */ - struct L1_tcon : Register<0x420, 32> - { - struct Frc_start : Bitfield<3, 1> { }; - }; - - /** - * Expired status - */ - struct L1_int_cstat : Register<0x430, 32, true> - { - struct Frcnt : Bitfield<1, 1> { }; - }; - - /** - * Interrupt enable - */ - struct L1_int_enb : Register<0x434, 32> - { - struct Frceie : Bitfield<1, 1> { }; - }; - - /** - * Write status - */ - struct L1_wstat : Register<0x440, 32, true> - { - struct Frcntb : Bitfield<2, 1> { }; - struct Tcon : Bitfield<3, 1> { }; - }; - - struct L1_frcnto : Register<0x414, 32> { }; - - /** - * Start and stop counting - */ - void _run_1(bool const run) - { - _acked_write - (L1_tcon::Frc_start::bits(run)); - } - - - /******************** - ** Helper methods ** - ********************/ - - /** - * Write to reg that replies via ack bit and clear ack bit - */ - template - void _acked_write(typename DEST::Register_base::access_t const v) - { - typedef typename DEST::Register_base Dest; - typedef typename ACK::Bitfield_base Ack; - write(v); - while (!read()); - write(1); - } - - /** - * Calculate amount of tics per ms for specific input clock - * - * \param clock input clock - */ - time_t static _calc_tics_per_ms(unsigned const clock) { - return clock / (PRESCALER + 1) / (1 << DIV_MUX) / 1000; } - - unsigned const _tics_per_ms; - - public: - - - /** - * Return kernel name of the interrupt of the timer of CPU 'cpu' - */ - static unsigned interrupt_id(unsigned const cpu) - { - switch (cpu) { - case 0: return Board::MCT_IRQ_L0; - case 1: return Board::MCT_IRQ_L1; - default: return 0; - } - } - - Timer(); - - /** - * Raise interrupt of CPU 'cpu' once after timeout 'tics' - */ - void start_one_shot(time_t const tics, unsigned const cpu) - { - switch (cpu) { - case 0: - write(1); - _run_0(0); - _acked_write(tics); - _run_0(1); - return; - case 1: - write(1); - _run_1(0); - _acked_write(tics); - _run_1(1); - return; - default: return; - } - } - - time_t value(unsigned const cpu) - { - switch (cpu) { - case 0: return read() ? 0 : read(); - case 1: return read() ? 0 : read(); - default: return 0; - } - } - - time_t tics_to_us(time_t const tics) const { - return (tics / _tics_per_ms) * 1000; } - - time_t us_to_tics(time_t const us) const { - return (us / 1000) * _tics_per_ms; } - - time_t max_value() { return (L0_frcnto::access_t)~0; } -}; - -namespace Kernel { class Timer : public Genode::Timer { }; } - -#endif /* _CORE__SPEC__EXYNOS5__TIMER_H_ */ diff --git a/repos/base-hw/src/core/spec/exynos5/timer_driver.h b/repos/base-hw/src/core/spec/exynos5/timer_driver.h new file mode 100644 index 000000000..5cffa4ba4 --- /dev/null +++ b/repos/base-hw/src/core/spec/exynos5/timer_driver.h @@ -0,0 +1,182 @@ +/* + * \brief Timer driver for core + * \author Martin stein + * \date 2013-01-10 + */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Kernel OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _TIMER_DRIVER_H_ +#define _TIMER_DRIVER_H_ + +/* Kernel includes */ +#include + +/* base-hw includes */ +#include + +namespace Kernel { class Timer_driver; } + + +struct Kernel::Timer_driver : Genode::Mmio +{ + enum { + PRESCALER = 1, + DIV_MUX = 0, + }; + + /** + * MCT configuration + */ + struct Mct_cfg : Register<0x0, 32> + { + struct Prescaler : Bitfield<0, 8> { }; + struct Div_mux : Bitfield<8, 3> { }; + }; + + + /******************* + ** Local timer 0 ** + *******************/ + + /** + * Free running counter buffer + */ + struct L0_frcntb : Register<0x310, 32> { }; + + /** + * Configuration + */ + struct L0_tcon : Register<0x320, 32> + { + struct Frc_start : Bitfield<3, 1> { }; + }; + + /** + * Expired status + */ + struct L0_int_cstat : Register<0x330, 32, true> + { + struct Frcnt : Bitfield<1, 1> { }; + }; + + /** + * Interrupt enable + */ + struct L0_int_enb : Register<0x334, 32> + { + struct Frceie : Bitfield<1, 1> { }; + }; + + /** + * Write status + */ + struct L0_wstat : Register<0x340, 32, true> + { + struct Frcntb : Bitfield<2, 1> { }; + struct Tcon : Bitfield<3, 1> { }; + }; + + struct L0_frcnto : Register<0x314, 32> { }; + + /** + * Start and stop counting + */ + void run_0(bool const run) + { + acked_write + (L0_tcon::Frc_start::bits(run)); + } + + + /******************* + ** Local timer 1 ** + *******************/ + + /** + * Free running counter buffer + */ + struct L1_frcntb : Register<0x410, 32> { }; + + /** + * Configuration + */ + struct L1_tcon : Register<0x420, 32> + { + struct Frc_start : Bitfield<3, 1> { }; + }; + + /** + * Expired status + */ + struct L1_int_cstat : Register<0x430, 32, true> + { + struct Frcnt : Bitfield<1, 1> { }; + }; + + /** + * Interrupt enable + */ + struct L1_int_enb : Register<0x434, 32> + { + struct Frceie : Bitfield<1, 1> { }; + }; + + /** + * Write status + */ + struct L1_wstat : Register<0x440, 32, true> + { + struct Frcntb : Bitfield<2, 1> { }; + struct Tcon : Bitfield<3, 1> { }; + }; + + struct L1_frcnto : Register<0x414, 32> { }; + + /** + * Start and stop counting + */ + void run_1(bool const run) + { + acked_write + (L1_tcon::Frc_start::bits(run)); + } + + + /******************** + ** Helper methods ** + ********************/ + + /** + * Write to reg that replies via ack bit and clear ack bit + */ + template + void acked_write(typename DEST::Register_base::access_t const v) + { + typedef typename DEST::Register_base Dest; + typedef typename ACK::Bitfield_base Ack; + write(v); + while (!read()); + write(1); + } + + /** + * Calculate amount of ticks per ms for specific input clock + * + * \param clock input clock + */ + time_t static calc_ticks_per_ms(unsigned const clock) { + return clock / (PRESCALER + 1) / (1 << DIV_MUX) / 1000; } + + unsigned const ticks_per_ms; + unsigned const cpu_id; + + Timer_driver(unsigned cpu_id); +}; + +#endif /* _TIMER_DRIVER_H_ */ diff --git a/repos/base-hw/src/core/spec/imx53/timer.cc b/repos/base-hw/src/core/spec/imx53/timer.cc index ed10b1eea..15cef4832 100644 --- a/repos/base-hw/src/core/spec/imx53/timer.cc +++ b/repos/base-hw/src/core/spec/imx53/timer.cc @@ -1,20 +1,59 @@ /* - * \brief Timer implementation for core + * \brief Timer driver for core * \author Stefan Kalkowski - * \date 2017-05-10 + * \author Martin Stein + * \date 2012-04-23 */ /* - * Copyright (C) 2017 Genode Labs GmbH + * Copyright (C) 2012-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. */ +/* core includes */ +#include #include -#include #include -Genode::Timer::Timer() -: Genode::Mmio(Genode::Platform::mmio_to_virt(Board::EPIT_1_MMIO_BASE)) { } +using namespace Genode; +using namespace Kernel; + +unsigned Timer::interrupt_id() const { return Board::EPIT_1_IRQ; } + + +Timer_driver::Timer_driver(unsigned) +: Mmio(Platform::mmio_to_virt(Board::EPIT_1_MMIO_BASE)) { } + + +void Timer::_start_one_shot(time_t const ticks) +{ + /* stop timer */ + _driver.reset(); + + /* configure timer for a one-shot */ + _driver.write(Driver::Cr::prepare_one_shot()); + _driver.write(ticks); + _driver.write(0); + + /* start timer */ + _driver.write(1); +} + + +time_t Timer::_ticks_to_us(time_t const ticks) const { + return (ticks / Driver::TICS_PER_MS) * 1000UL; } + + +time_t Timer::us_to_ticks(time_t const us) const { + return (us / 1000UL) * Driver::TICS_PER_MS; } + + +time_t Timer::_max_value() const { + return (Driver::Cnt::access_t)~0; } + + +time_t Timer::_value() { + return _driver.read() ? 0 : _driver.read(); } diff --git a/repos/base-hw/src/core/spec/imx53/timer.h b/repos/base-hw/src/core/spec/imx53/timer.h deleted file mode 100644 index 6601b9393..000000000 --- a/repos/base-hw/src/core/spec/imx53/timer.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * \brief Timer driver for core - * \author Martin Stein - * \date 2012-04-23 - */ - -/* - * Copyright (C) 2012-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__SPEC__IMX53__TIMER_H_ -#define _CORE__SPEC__IMX53__TIMER_H_ - -/* base-hw includes */ -#include - -/* Genode includes */ -#include - -/* core includes */ -#include - -namespace Genode { class Timer; } - -/** - * Timer driver for core - */ -class Genode::Timer : public Mmio -{ - private: - - using time_t = Kernel::time_t; - - enum { TICS_PER_MS = 33333 }; - - /** - * Control register - */ - struct Cr : Register<0x0, 32> - { - struct En : Bitfield<0, 1> { }; /* enable timer */ - - struct En_mod : Bitfield<1, 1> /* reload on enable */ - { - enum { RELOAD = 1 }; - }; - - struct Oci_en : Bitfield<2, 1> { }; /* interrupt on compare */ - - struct Rld : Bitfield<3, 1> /* reload or roll-over */ - { - enum { RELOAD_FROM_LR = 1 }; - }; - - struct Prescaler : Bitfield<4, 12> /* clock input divisor */ - { - enum { DIVIDE_BY_1 = 0 }; - }; - - struct Swr : Bitfield<16, 1> { }; /* software reset bit */ - struct Iovw : Bitfield<17, 1> { }; /* enable overwrite */ - struct Dbg_en : Bitfield<18, 1> { }; /* enable in debug mode */ - struct Wait_en : Bitfield<19, 1> { }; /* enable in wait mode */ - struct Doz_en : Bitfield<20, 1> { }; /* enable in doze mode */ - struct Stop_en : Bitfield<21, 1> { }; /* enable in stop mode */ - - struct Om : Bitfield<22, 2> /* mode of the output pin */ - { - enum { DISCONNECTED = 0 }; - }; - - struct Clk_src : Bitfield<24, 2> /* select clock input */ - { - enum { HIGH_FREQ_REF_CLK = 2 }; - }; - - /** - * Register value that configures the timer for a one-shot run - */ - static access_t prepare_one_shot() - { - return En::bits(0) | - En_mod::bits(En_mod::RELOAD) | - Oci_en::bits(1) | - Rld::bits(Rld::RELOAD_FROM_LR) | - Prescaler::bits(Prescaler::DIVIDE_BY_1) | - Swr::bits(0) | - Iovw::bits(0) | - Dbg_en::bits(0) | - Wait_en::bits(0) | - Doz_en::bits(0) | - Stop_en::bits(0) | - Om::bits(Om::DISCONNECTED) | - Clk_src::bits(Clk_src::HIGH_FREQ_REF_CLK); - } - }; - - /** - * Status register - */ - struct Sr : Register<0x4, 32> - { - struct Ocif : Bitfield<0, 1> { }; /* IRQ status, write 1 clears */ - }; - - struct Lr : Register<0x8, 32> { }; /* load value register */ - struct Cmpr : Register<0xc, 32> { }; /* compare value register */ - struct Cnt : Register<0x10, 32> { }; /* counter register */ - - /** - * Disable timer and clear its interrupt output - */ - void _reset() - { - /* wait until ongoing reset operations are finished */ - while (read()) ; - - /* disable timer */ - write(0); - - /* clear interrupt */ - write(1); - } - - public: - - /** - * Return kernel name of timer interrupt - */ - static unsigned interrupt_id(unsigned const) - { - return Board::EPIT_1_IRQ; - } - - Timer(); - - /** - * Start single timeout run - * - * \param tics delay of timer interrupt - */ - void start_one_shot(time_t const tics, unsigned const) - { - /* stop timer */ - _reset(); - - /* configure timer for a one-shot */ - write(Cr::prepare_one_shot()); - write(tics); - write(0); - - /* start timer */ - write(1); - } - - time_t tics_to_us(time_t const tics) const { - return (tics / TICS_PER_MS) * 1000; } - - time_t us_to_tics(time_t const us) const { - return (us / 1000) * TICS_PER_MS; } - - time_t max_value() { return (Cnt::access_t)~0; } - - /** - * Return current native timer value - */ - time_t value(unsigned const) { - return read() ? 0 : read(); } -}; - -namespace Kernel { using Timer = Genode::Timer; } - -#endif /* _CORE__SPEC__IMX53__TIMER_H_ */ diff --git a/repos/base-hw/src/core/spec/imx53/timer_driver.h b/repos/base-hw/src/core/spec/imx53/timer_driver.h new file mode 100644 index 000000000..09a2ad87b --- /dev/null +++ b/repos/base-hw/src/core/spec/imx53/timer_driver.h @@ -0,0 +1,121 @@ +/* + * \brief Timer driver for core + * \author Martin Stein + * \date 2012-04-23 + */ + +/* + * Copyright (C) 2012-2017 Kernel Labs GmbH + * + * This file is part of the Kernel OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _TIMER_DRIVER_H_ +#define _TIMER_DRIVER_H_ + +/* Kernel includes */ +#include + +namespace Kernel { class Timer_driver; } + +/** + * Timer driver for core + */ +struct Kernel::Timer_driver : Genode::Mmio +{ + enum { TICS_PER_MS = 33333 }; + + /** + * Control register + */ + struct Cr : Register<0x0, 32> + { + struct En : Bitfield<0, 1> { }; /* enable timer */ + + struct En_mod : Bitfield<1, 1> /* reload on enable */ + { + enum { RELOAD = 1 }; + }; + + struct Oci_en : Bitfield<2, 1> { }; /* interrupt on compare */ + + struct Rld : Bitfield<3, 1> /* reload or roll-over */ + { + enum { RELOAD_FROM_LR = 1 }; + }; + + struct Prescaler : Bitfield<4, 12> /* clock input divisor */ + { + enum { DIVIDE_BY_1 = 0 }; + }; + + struct Swr : Bitfield<16, 1> { }; /* software reset bit */ + struct Iovw : Bitfield<17, 1> { }; /* enable overwrite */ + struct Dbg_en : Bitfield<18, 1> { }; /* enable in debug mode */ + struct Wait_en : Bitfield<19, 1> { }; /* enable in wait mode */ + struct Doz_en : Bitfield<20, 1> { }; /* enable in doze mode */ + struct Stop_en : Bitfield<21, 1> { }; /* enable in stop mode */ + + struct Om : Bitfield<22, 2> /* mode of the output pin */ + { + enum { DISCONNECTED = 0 }; + }; + + struct Clk_src : Bitfield<24, 2> /* select clock input */ + { + enum { HIGH_FREQ_REF_CLK = 2 }; + }; + + /** + * Register value that configures the timer for a one-shot run + */ + static access_t prepare_one_shot() + { + return En::bits(0) | + En_mod::bits(En_mod::RELOAD) | + Oci_en::bits(1) | + Rld::bits(Rld::RELOAD_FROM_LR) | + Prescaler::bits(Prescaler::DIVIDE_BY_1) | + Swr::bits(0) | + Iovw::bits(0) | + Dbg_en::bits(0) | + Wait_en::bits(0) | + Doz_en::bits(0) | + Stop_en::bits(0) | + Om::bits(Om::DISCONNECTED) | + Clk_src::bits(Clk_src::HIGH_FREQ_REF_CLK); + } + }; + + /** + * Status register + */ + struct Sr : Register<0x4, 32> + { + struct Ocif : Bitfield<0, 1> { }; /* IRQ status, write 1 clears */ + }; + + struct Lr : Register<0x8, 32> { }; /* load value register */ + struct Cmpr : Register<0xc, 32> { }; /* compare value register */ + struct Cnt : Register<0x10, 32> { }; /* counter register */ + + /** + * Disable timer and clear its interrupt output + */ + void reset() + { + /* wait until ongoing reset operations are finished */ + while (read()) ; + + /* disable timer */ + write(0); + + /* clear interrupt */ + write(1); + } + + Timer_driver(unsigned); +}; + +#endif /* _TIMER_DRIVER_H_ */ diff --git a/repos/base-hw/src/core/spec/riscv/timer.cc b/repos/base-hw/src/core/spec/riscv/timer.cc new file mode 100644 index 000000000..8a442427f --- /dev/null +++ b/repos/base-hw/src/core/spec/riscv/timer.cc @@ -0,0 +1,57 @@ +/* + * \brief Timer driver for core + * \author Sebastian Sumpf + * \date 2015-08-22 + */ + +/* + * Copyright (C) 2015-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. + */ + +/* Core includes */ +#include +#include + +using namespace Genode; +using namespace Kernel; + + +Timer_driver::Timer_driver(unsigned) +{ + /* enable timer interrupt */ + enum { STIE = 0x20 }; + asm volatile ("csrs sie, %0" : : "r"(STIE)); +} + + +void Timer::_start_one_shot(time_t const ticks, unsigned const) +{ + _driver.timeout = _driver.stime() + ticks; + Machine::set_sys_timer(_driver.timeout); +} + + +time_t Timer::_ticks_to_us(time_t const ticks) const { + return (ticks / Driver::TICS_PER_MS) * 1000; } + + +time_t Timer::us_to_ticks(time_t const us) const { + return (us / 1000) * Driver::TICS_PER_MS; } + + +time_t Timer::_max_value() { + return (addr_t)~0; } + + +time_t Timer::_value(unsigned const) +{ + addr_t time = _driver.stime(); + return time < _driver.timeout ? _driver.timeout - time : 0; +} + + +unsigned Timer::interrupt_id() const { + return 1; } diff --git a/repos/base-hw/src/core/spec/riscv/timer.h b/repos/base-hw/src/core/spec/riscv/timer.h deleted file mode 100644 index 43353c086..000000000 --- a/repos/base-hw/src/core/spec/riscv/timer.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * \brief Timer driver for core - * \author Sebastian Sumpf - * \date 2015-08-22 - */ - -/* - * Copyright (C) 2015-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__SPEC__RISCV__TIMER_H_ -#define _CORE__SPEC__RISCV__TIMER_H_ - -/* base-hw includes */ -#include -#include - -/* Genode includes */ -#include - - -namespace Genode { class Timer; } - -/** - * Timer driver for core - */ -struct Genode::Timer -{ - private: - - using time_t = Kernel::time_t; - - enum { - SPIKE_TIMER_HZ = 500000, - TICS_PER_MS = SPIKE_TIMER_HZ / 1000, - }; - - addr_t _timeout = 0; - - addr_t _stime() - { - addr_t t; - asm volatile ("csrr %0, stime\n" : "=r"(t)); - return t; - } - - public: - - Timer() - { - /* enable timer interrupt */ - enum { STIE = 0x20 }; - asm volatile ("csrs sie, %0" : : "r"(STIE)); - } - - /** - * Start single timeout run - * - * \param tics delay of timer interrupt - */ - void start_one_shot(time_t const tics, unsigned const) - { - _timeout = _stime() + tics; - Hw::set_sys_timer(_timeout); - } - - time_t tics_to_us(time_t const tics) const { - return (tics / TICS_PER_MS) * 1000; } - - time_t us_to_tics(time_t const us) const { - return (us / 1000) * TICS_PER_MS; } - - time_t max_value() { return (addr_t)~0; } - - /** - * Return current native timer value - */ - time_t value(unsigned const) - { - addr_t time = _stime(); - return time < _timeout ? _timeout - time : 0; - } - - static unsigned interrupt_id(unsigned const) { return 1; } -}; - -namespace Kernel { class Timer : public Genode::Timer { }; } - -#endif /* _CORE__SPEC__RISCV__TIMER_H_ */ diff --git a/repos/base-hw/src/core/spec/riscv/timer_driver.h b/repos/base-hw/src/core/spec/riscv/timer_driver.h new file mode 100644 index 000000000..035da617b --- /dev/null +++ b/repos/base-hw/src/core/spec/riscv/timer_driver.h @@ -0,0 +1,45 @@ +/* + * \brief Timer driver for core + * \author Sebastian Sumpf + * \date 2015-08-22 + */ + +/* + * Copyright (C) 2015-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 _TIMER_H_ +#define _TIMER_H_ + +/* Genode includes */ +#include + +namespace Kernel { class Timer_driver; } + + +/** + * Timer driver for core + */ +struct Kernel::Timer_driver +{ + enum { + SPIKE_TIMER_HZ = 500000, + TICS_PER_MS = SPIKE_TIMER_HZ / 1000, + }; + + addr_t timeout = 0; + + addr_t stime() + { + Genode::addr_t t; + asm volatile ("csrr %0, stime\n" : "=r"(t)); + return t; + } + + Timer_driver(unsigned); +}; + +#endif /* _TIMER_H_ */ diff --git a/repos/base-hw/src/core/spec/rpi/timer.cc b/repos/base-hw/src/core/spec/rpi/timer.cc index bbdbf4d52..68e18a4c2 100644 --- a/repos/base-hw/src/core/spec/rpi/timer.cc +++ b/repos/base-hw/src/core/spec/rpi/timer.cc @@ -2,6 +2,7 @@ * \brief Timer implementation specific to Rpi * \author Norman Feske * \author Stefan Kalkowski + * \author Martin Stein * \date 2016-01-07 */ @@ -12,40 +13,45 @@ * under the terms of the GNU Affero General Public License version 3. */ +/* core includes */ #include -#include +#include using namespace Genode; -using Kernel::time_t; +using namespace Kernel; -Timer::Timer() +Timer_driver::Timer_driver(unsigned) : Mmio(Platform::mmio_to_virt(Board::SYSTEM_TIMER_MMIO_BASE)) { } -void Timer::start_one_shot(time_t const tics, unsigned const) +void Timer::_start_one_shot(time_t const ticks) { - write(1); - read(); - write(0); - write(read() + tics); + _driver.write(1); + _driver.read(); + _driver.write(0); + _driver.write(_driver.read() + ticks); } -time_t Timer::tics_to_us(time_t const tics) const { - return (tics / TICS_PER_MS) * 1000; } +time_t Timer::_ticks_to_us(time_t const ticks) const { + return (ticks / Driver::TICS_PER_MS) * 1000; } -time_t Timer::us_to_tics(time_t const us) const { - return (us / 1000) * TICS_PER_MS; } +time_t Timer::us_to_ticks(time_t const us) const { + return (us / 1000) * Driver::TICS_PER_MS; } -time_t Timer::max_value() { return (Clo::access_t)~0; } +time_t Timer::_max_value() const { + return (Driver::Clo::access_t)~0; } -time_t Timer::value(unsigned const) +time_t Timer::_value() { - Cmp::access_t const cmp = read(); - Clo::access_t const clo = read(); + Driver::Cmp::access_t const cmp = _driver.read(); + Driver::Clo::access_t const clo = _driver.read(); return cmp > clo ? cmp - clo : 0; } + + +unsigned Timer::interrupt_id() const { return Board::SYSTEM_TIMER_IRQ; } diff --git a/repos/base-hw/src/core/spec/rpi/timer.h b/repos/base-hw/src/core/spec/rpi/timer.h deleted file mode 100644 index 3498cca8b..000000000 --- a/repos/base-hw/src/core/spec/rpi/timer.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * \brief Timer driver for core - * \author Norman Feske - * \date 2013-04-05 - */ - -/* - * Copyright (C) 2013-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__SPEC__RPI__TIMER_H_ -#define _CORE__SPEC__RPI__TIMER_H_ - -/* base-hw includes */ -#include - -/* Genode includes */ -#include - -/* core includes */ -#include - -namespace Genode { class Timer; } - -/** - * Timer driver for core - * - * Timer channel 0 apparently doesn't work on the RPI, so we use channel 1 - */ -class Genode::Timer : public Mmio -{ - private: - - using time_t = Kernel::time_t; - - enum { TICS_PER_MS = Board::SYSTEM_TIMER_CLOCK / 1000 }; - - struct Cs : Register<0x0, 32> { struct M1 : Bitfield<1, 1> { }; }; - struct Clo : Register<0x4, 32> { }; - struct Cmp : Register<0x10, 32> { }; - - public: - - Timer(); - - static unsigned interrupt_id(unsigned const) { - return Board::SYSTEM_TIMER_IRQ; } - - void start_one_shot(time_t const tics, unsigned const); - time_t tics_to_us(time_t const tics) const; - time_t us_to_tics(time_t const us) const; - time_t max_value(); - time_t value(unsigned const); -}; - -namespace Kernel { using Genode::Timer; } - -#endif /* _CORE__SPEC__RPI__TIMER_H_ */ diff --git a/repos/base-hw/src/core/spec/rpi/timer_driver.h b/repos/base-hw/src/core/spec/rpi/timer_driver.h new file mode 100644 index 000000000..daa703a4c --- /dev/null +++ b/repos/base-hw/src/core/spec/rpi/timer_driver.h @@ -0,0 +1,41 @@ +/* + * \brief Timer driver for core + * \author Norman Feske + * \date 2013-04-05 + */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Kernel OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _TIMER_DRIVER_H_ +#define _TIMER_DRIVER_H_ + +/* Kernel includes */ +#include + +/* core includes */ +#include + +namespace Kernel { class Timer_driver; } + +/** + * Timer driver for core + * + * Timer channel 0 apparently doesn't work on the RPI, so we use channel 1 + */ +struct Kernel::Timer_driver : Genode::Mmio +{ + enum { TICS_PER_MS = Board::SYSTEM_TIMER_CLOCK / 1000 }; + + struct Cs : Register<0x0, 32> { struct M1 : Bitfield<1, 1> { }; }; + struct Clo : Register<0x4, 32> { }; + struct Cmp : Register<0x10, 32> { }; + + Timer_driver(unsigned); +}; + +#endif /* _TIMER_DRIVER_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/kernel/cpu.cc b/repos/base-hw/src/core/spec/x86_64/kernel/cpu.cc index d451f341f..b3351c5c1 100644 --- a/repos/base-hw/src/core/spec/x86_64/kernel/cpu.cc +++ b/repos/base-hw/src/core/spec/x86_64/kernel/cpu.cc @@ -38,13 +38,13 @@ void Kernel::Cpu::init(Pic &pic) Idt::init(); Tss::init(); - Timer::disable_pit(); + Timer::init_cpu_local(); fpu().init(); /* enable timer interrupt */ unsigned const cpu = Cpu::executing_id(); - pic.unmask(Timer::interrupt_id(cpu), cpu); + pic.unmask(_timer.interrupt_id(), cpu); } diff --git a/repos/base-hw/src/core/spec/x86_64/muen/timer.cc b/repos/base-hw/src/core/spec/x86_64/muen/timer.cc index 8037833dc..cfc8b098b 100644 --- a/repos/base-hw/src/core/spec/x86_64/muen/timer.cc +++ b/repos/base-hw/src/core/spec/x86_64/muen/timer.cc @@ -1,6 +1,7 @@ /* * \brief Timer driver for core * \author Reto Buerki + * \author Martin Stein * \date 2015-04-14 */ @@ -11,12 +12,21 @@ * under the terms of the GNU Affero General Public License version 3. */ -#include +/* base includes */ +#include + +/* core includes */ +#include #include +#include +#include -Genode::Timer::Timer() : _tics_per_ms(sinfo()->get_tsc_khz()) +using namespace Genode; +using namespace Kernel; + + +Timer_driver::Timer_driver(unsigned) : ticks_per_ms(sinfo()->get_tsc_khz()) { - /* first sinfo instance, output status */ sinfo()->log_status(); @@ -26,17 +36,57 @@ Genode::Timer::Timer() : _tics_per_ms(sinfo()->get_tsc_khz()) throw Invalid_region(); } - _event_page = (Subject_timed_event *)Platform::mmio_to_virt(region.address); - _event_page->event_nr = Board::TIMER_EVENT_KERNEL; + event_page = (Subject_timed_event *)Platform::mmio_to_virt(region.address); + event_page->event_nr = Board::TIMER_EVENT_KERNEL; log("muen-timer: Page @", Hex(region.address), ", " - "frequency ", _tics_per_ms, " kHz, " - "event ", (unsigned)_event_page->event_nr); + "frequency ", ticks_per_ms, " kHz, " + "event ", (unsigned)event_page->event_nr); if (sinfo()->get_memregion_info("monitor_timed_event", ®ion)) { log("muen-timer: Found guest timed event page @", Hex(region.address), " -> enabling preemption"); - _guest_event_page = (Subject_timed_event *)Platform::mmio_to_virt(region.address); - _guest_event_page->event_nr = Board::TIMER_EVENT_PREEMPT; + guest_event_page = (Subject_timed_event *)Platform::mmio_to_virt(region.address); + guest_event_page->event_nr = Board::TIMER_EVENT_PREEMPT; } } + +void Timer::init_cpu_local() { } + + +unsigned Timer::interrupt_id() const { + return Board::TIMER_VECTOR_KERNEL; } + + +void Timer::_start_one_shot(time_t const ticks) +{ + const uint64_t t = _driver.rdtsc() + ticks; + _driver.event_page->tsc_trigger = t; + + if (_driver.guest_event_page) + _driver.guest_event_page->tsc_trigger = t; +} + + +time_t Timer::_ticks_to_us(time_t const ticks) const { + return (ticks / _driver.ticks_per_ms) * 1000; } + + +time_t Timer::us_to_ticks(time_t const us) const { + return (us / 1000) * _driver.ticks_per_ms; } + + +time_t Timer::_max_value() const { + return (time_t)~0; } + + +time_t Timer::_value() +{ + const uint64_t now = _driver.rdtsc(); + if (_driver.event_page->tsc_trigger != Driver::TIMER_DISABLED + && _driver.event_page->tsc_trigger > now) + { + return _driver.event_page->tsc_trigger - now; + } + return 0; +} diff --git a/repos/base-hw/src/core/spec/x86_64/muen/timer.h b/repos/base-hw/src/core/spec/x86_64/muen/timer.h deleted file mode 100644 index 8107e9260..000000000 --- a/repos/base-hw/src/core/spec/x86_64/muen/timer.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * \brief Timer driver for core - * \author Reto Buerki - * \date 2015-04-14 - */ - -/* - * Copyright (C) 2015-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__SPEC__X86_64__MUEN__TIMER_H_ -#define _CORE__SPEC__X86_64__MUEN__TIMER_H_ - -/* base includes */ -#include -#include - -/* core includes */ -#include -#include - -namespace Genode -{ - /** - * Timer driver for core on Muen - */ - class Timer; -} - -class Genode::Timer -{ - private: - - using time_t = Kernel::time_t; - - enum { TIMER_DISABLED = ~0ULL }; - - uint64_t _tics_per_ms; - - struct Subject_timed_event - { - uint64_t tsc_trigger; - uint8_t event_nr :5; - } __attribute__((packed)); - - struct Subject_timed_event * _event_page = 0; - struct Subject_timed_event * _guest_event_page = 0; - - - inline uint64_t rdtsc() - { - uint32_t lo, hi; - asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); - return (uint64_t)hi << 32 | lo; - } - - class Invalid_region {}; - - public: - - Timer(); - - static unsigned interrupt_id(int) { - return Board::TIMER_VECTOR_KERNEL; } - - inline void start_one_shot(time_t const tics, unsigned) - { - const uint64_t t = rdtsc() + tics; - _event_page->tsc_trigger = t; - - if (_guest_event_page) - _guest_event_page->tsc_trigger = t; - } - - time_t tics_to_us(time_t const tics) const { - return (tics / _tics_per_ms) * 1000; } - - time_t us_to_tics(time_t const us) const { - return (us / 1000) * _tics_per_ms; } - - time_t max_value() { return (time_t)~0; } - - time_t value(unsigned) - { - const uint64_t now = rdtsc(); - if (_event_page->tsc_trigger != TIMER_DISABLED - && _event_page->tsc_trigger > now) { - return _event_page->tsc_trigger - now; - } - return 0; - } - - static void disable_pit(void) { } -}; - -namespace Kernel { class Timer : public Genode::Timer { }; } - -#endif /* _CORE__SPEC__X86_64__MUEN__TIMER_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/muen/timer_driver.h b/repos/base-hw/src/core/spec/x86_64/muen/timer_driver.h new file mode 100644 index 000000000..bd1b1a6f5 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/muen/timer_driver.h @@ -0,0 +1,50 @@ +/* + * \brief Timer driver for core + * \author Reto Buerki + * \date 2015-04-14 + */ + +/* + * Copyright (C) 2015-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 _TIMER_DRIVER_H_ +#define _TIMER_DRIVER_H_ + +/* Genode includes */ +#include + +namespace Kernel { class Timer_driver; } + + +struct Kernel::Timer_driver +{ + enum { TIMER_DISABLED = ~0ULL }; + + Genode::uint64_t ticks_per_ms; + + struct Subject_timed_event + { + Genode::uint64_t tsc_trigger; + Genode::uint8_t event_nr :5; + } __attribute__((packed)); + + struct Subject_timed_event * event_page = 0; + struct Subject_timed_event * guest_event_page = 0; + + inline Genode::uint64_t rdtsc() + { + Genode::uint32_t lo, hi; + asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); + return (Genode::uint64_t)hi << 32 | lo; + } + + class Invalid_region { }; + + Timer_driver(unsigned); +}; + +#endif /* _TIMER_DRIVER_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/timer.cc b/repos/base-hw/src/core/spec/x86_64/timer.cc index 6c71dc103..7ce390d3b 100644 --- a/repos/base-hw/src/core/spec/x86_64/timer.cc +++ b/repos/base-hw/src/core/spec/x86_64/timer.cc @@ -2,6 +2,7 @@ * \brief Timer driver for core * \author Adrian-Ken Rueegsegger * \author Reto Buerki + * \author Martin Stein * \date 2015-02-06 */ @@ -15,13 +16,14 @@ #include /* core includes */ -#include +#include #include using namespace Genode; -using Kernel::time_t; +using namespace Kernel; -uint32_t Timer::_pit_calc_timer_freq(void) + +uint32_t Timer_driver::pit_calc_timer_freq(void) { uint32_t t_start, t_end; @@ -48,7 +50,8 @@ uint32_t Timer::_pit_calc_timer_freq(void) } -Timer::Timer() : Mmio(Platform::mmio_to_virt(Hw::Cpu_memory_map::MMIO_LAPIC_BASE)) +Timer_driver::Timer_driver(unsigned) +: Mmio(Platform::mmio_to_virt(Hw::Cpu_memory_map::MMIO_LAPIC_BASE)) { write( Divide_configuration::Divide_value::MAX); @@ -60,31 +63,41 @@ Timer::Timer() : Mmio(Platform::mmio_to_virt(Hw::Cpu_memory_map::MMIO_LAPIC_BASE write(0); /* Calculate timer frequency */ - _tics_per_ms = _pit_calc_timer_freq(); + ticks_per_ms = pit_calc_timer_freq(); } -void Timer::disable_pit() +void Timer::init_cpu_local() { - outb(PIT_MODE, 0x30); - outb(PIT_CH0_DATA, 0); - outb(PIT_CH0_DATA, 0); + /** + * Disable PIT timer channel. This is necessary since BIOS sets up + * channel 0 to fire periodically. + */ + outb(Driver::PIT_MODE, 0x30); + outb(Driver::PIT_CH0_DATA, 0); + outb(Driver::PIT_CH0_DATA, 0); } -void Timer::start_one_shot(time_t const tics, unsigned const) { - write(tics); } +void Timer::_start_one_shot(time_t const ticks) { + _driver.write(ticks); } -time_t Timer::tics_to_us(time_t const tics) const { - return (tics / _tics_per_ms) * 1000; } +time_t Timer::_ticks_to_us(time_t const ticks) const { + return (ticks / _driver.ticks_per_ms) * 1000; } -time_t Timer::us_to_tics(time_t const us) const { - return (us / 1000) * _tics_per_ms; } +time_t Timer::us_to_ticks(time_t const us) const { + return (us / 1000) * _driver.ticks_per_ms; } -time_t Timer::max_value() { return (Tmr_initial::access_t)~0; } +time_t Timer::_max_value() const { + return (Driver::Tmr_initial::access_t)~0; } -time_t Timer::value(unsigned const) { return read(); } +time_t Timer::_value() { + return _driver.read(); } + + +unsigned Timer::interrupt_id() const { + return Board::TIMER_VECTOR_KERNEL; } diff --git a/repos/base-hw/src/core/spec/x86_64/timer.h b/repos/base-hw/src/core/spec/x86_64/timer.h deleted file mode 100644 index 9b8214bea..000000000 --- a/repos/base-hw/src/core/spec/x86_64/timer.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * \brief Timer driver for core - * \author Adrian-Ken Rueegsegger - * \author Reto Buerki - * \date 2015-02-06 - */ - -/* - * Copyright (C) 2015-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__SPEC__X86_64__TIMER_H_ -#define _CORE__SPEC__X86_64__TIMER_H_ - -/* base-hw includes */ -#include - -/* Genode includes */ -#include -#include - -/* core includes */ -#include -#include - -namespace Genode { class Timer; } - -/** - * LAPIC-based timer driver for core - */ -class Genode::Timer : public Mmio -{ - private: - - using time_t = Kernel::time_t; - - enum { - /* PIT constants */ - PIT_TICK_RATE = 1193182ul, - PIT_SLEEP_MS = 50, - PIT_SLEEP_TICS = (PIT_TICK_RATE / 1000) * PIT_SLEEP_MS, - PIT_CH0_DATA = 0x40, - PIT_CH2_DATA = 0x42, - PIT_CH2_GATE = 0x61, - PIT_MODE = 0x43, - }; - - /* Timer registers */ - struct Tmr_lvt : Register<0x320, 32> - { - struct Vector : Bitfield<0, 8> { }; - struct Delivery : Bitfield<8, 3> { }; - struct Mask : Bitfield<16, 1> { }; - struct Timer_mode : Bitfield<17, 2> { }; - }; - struct Tmr_initial : Register <0x380, 32> { }; - struct Tmr_current : Register <0x390, 32> { }; - - struct Divide_configuration : Register <0x03e0, 32> - { - struct Divide_value_0_2 : Bitfield<0, 2> { }; - struct Divide_value_2_1 : Bitfield<3, 1> { }; - struct Divide_value : - Bitset_2 - { - enum { MAX = 6 }; - }; - }; - - uint32_t _tics_per_ms = 0; - - /* Measure LAPIC timer frequency using PIT channel 2 */ - uint32_t _pit_calc_timer_freq(void); - - public: - - Timer(); - - /** - * Disable PIT timer channel. This is necessary since BIOS sets up - * channel 0 to fire periodically. - */ - static void disable_pit(); - - static unsigned interrupt_id(unsigned const) { - return Board::TIMER_VECTOR_KERNEL; } - - void start_one_shot(time_t const tics, unsigned const); - time_t tics_to_us(time_t const tics) const; - time_t us_to_tics(time_t const us) const; - time_t max_value(); - time_t value(unsigned const); -}; - -namespace Kernel { using Genode::Timer; } - -#endif /* _CORE__SPEC__X86_64__TIMER_H_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/timer_driver.h b/repos/base-hw/src/core/spec/x86_64/timer_driver.h new file mode 100644 index 000000000..ac95fd0de --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/timer_driver.h @@ -0,0 +1,74 @@ +/* + * \brief Timer driver for core + * \author Adrian-Ken Rueegsegger + * \author Reto Buerki + * \date 2015-02-06 + */ + +/* + * Copyright (C) 2015-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 _TIMER_DRIVER_H_ +#define _TIMER_DRIVER_H_ + +/* Genode includes */ +#include +#include + +/* core includes */ +#include +#include + +namespace Kernel { class Timer_driver; } + +/** + * LAPIC-based timer driver for core + */ +struct Kernel::Timer_driver : Genode::Mmio +{ + enum { + /* PIT constants */ + PIT_TICK_RATE = 1193182ul, + PIT_SLEEP_MS = 50, + PIT_SLEEP_TICS = (PIT_TICK_RATE / 1000) * PIT_SLEEP_MS, + PIT_CH0_DATA = 0x40, + PIT_CH2_DATA = 0x42, + PIT_CH2_GATE = 0x61, + PIT_MODE = 0x43, + }; + + /* Timer registers */ + struct Tmr_lvt : Register<0x320, 32> + { + struct Vector : Bitfield<0, 8> { }; + struct Delivery : Bitfield<8, 3> { }; + struct Mask : Bitfield<16, 1> { }; + struct Timer_mode : Bitfield<17, 2> { }; + }; + struct Tmr_initial : Register <0x380, 32> { }; + struct Tmr_current : Register <0x390, 32> { }; + + struct Divide_configuration : Register <0x03e0, 32> + { + struct Divide_value_0_2 : Bitfield<0, 2> { }; + struct Divide_value_2_1 : Bitfield<3, 1> { }; + struct Divide_value : + Genode::Bitset_2 + { + enum { MAX = 6 }; + }; + }; + + Genode::uint32_t ticks_per_ms = 0; + + /* Measure LAPIC timer frequency using PIT channel 2 */ + Genode::uint32_t pit_calc_timer_freq(void); + + Timer_driver(unsigned); +}; + +#endif /* _TIMER_DRIVER_H_ */