diff --git a/repos/os/lib/mk/spec/fiasco/timer.mk b/repos/os/lib/mk/spec/fiasco/timer.mk index 750cec3bf..c0392abb8 100644 --- a/repos/os/lib/mk/spec/fiasco/timer.mk +++ b/repos/os/lib/mk/spec/fiasco/timer.mk @@ -1,6 +1,5 @@ +INC_DIR += $(REP_DIR)/src/drivers/timer/spec/periodic + +SRC_CC += spec/periodic/time_source.cc spec/fiasco/time_source.cc + include $(REP_DIR)/lib/mk/timer.inc - -INC_DIR += $(REP_DIR)/src/drivers/timer/include_periodic - -SRC_CC += platform_timer.cc -vpath platform_timer.cc $(REP_DIR)/src/drivers/timer/spec/fiasco diff --git a/repos/os/lib/mk/spec/foc/timer.mk b/repos/os/lib/mk/spec/foc/timer.mk index 750cec3bf..c0392abb8 100644 --- a/repos/os/lib/mk/spec/foc/timer.mk +++ b/repos/os/lib/mk/spec/foc/timer.mk @@ -1,6 +1,5 @@ +INC_DIR += $(REP_DIR)/src/drivers/timer/spec/periodic + +SRC_CC += spec/periodic/time_source.cc spec/fiasco/time_source.cc + include $(REP_DIR)/lib/mk/timer.inc - -INC_DIR += $(REP_DIR)/src/drivers/timer/include_periodic - -SRC_CC += platform_timer.cc -vpath platform_timer.cc $(REP_DIR)/src/drivers/timer/spec/fiasco diff --git a/repos/os/lib/mk/spec/hw/timer.mk b/repos/os/lib/mk/spec/hw/timer.mk index f796538d2..1fe424157 100644 --- a/repos/os/lib/mk/spec/hw/timer.mk +++ b/repos/os/lib/mk/spec/hw/timer.mk @@ -1,3 +1,5 @@ INC_DIR += $(REP_DIR)/src/drivers/timer/spec/hw +SRC_CC += spec/hw/time_source.cc + include $(REP_DIR)/lib/mk/timer.inc diff --git a/repos/os/lib/mk/spec/linux/timer.mk b/repos/os/lib/mk/spec/linux/timer.mk index 66cef60a2..7a809b0d9 100644 --- a/repos/os/lib/mk/spec/linux/timer.mk +++ b/repos/os/lib/mk/spec/linux/timer.mk @@ -1,8 +1,7 @@ -include $(REP_DIR)/lib/mk/timer.inc +INC_DIR += $(REP_DIR)/src/drivers/timer/spec/periodic -INC_DIR += $(REP_DIR)/src/drivers/timer/include_periodic +SRC_CC += spec/periodic/time_source.cc spec/linux/time_source.cc LIBS += syscall -SRC_CC += platform_timer.cc -vpath platform_timer.cc $(REP_DIR)/src/drivers/timer/spec/linux +include $(REP_DIR)/lib/mk/timer.inc diff --git a/repos/os/lib/mk/spec/nova/timer.mk b/repos/os/lib/mk/spec/nova/timer.mk index 19b965e10..efb3dabe4 100644 --- a/repos/os/lib/mk/spec/nova/timer.mk +++ b/repos/os/lib/mk/spec/nova/timer.mk @@ -1,3 +1,5 @@ -include $(REP_DIR)/lib/mk/timer.inc - INC_DIR += $(REP_DIR)/src/drivers/timer/spec/nova + +SRC_CC += spec/nova/time_source.cc + +include $(REP_DIR)/lib/mk/timer.inc diff --git a/repos/os/lib/mk/spec/okl4_x86/timer.mk b/repos/os/lib/mk/spec/okl4_x86/timer.mk index 1416a43ba..56d5e7214 100644 --- a/repos/os/lib/mk/spec/okl4_x86/timer.mk +++ b/repos/os/lib/mk/spec/okl4_x86/timer.mk @@ -1,3 +1,5 @@ -include $(REP_DIR)/lib/mk/timer.inc +INC_DIR += $(REP_DIR)/src/drivers/timer/spec/pit -INC_DIR += $(REP_DIR)/src/drivers/timer/include_pit +SRC_CC += spec/pit/time_source.cc + +include $(REP_DIR)/lib/mk/timer.inc diff --git a/repos/os/lib/mk/spec/pistachio/timer.mk b/repos/os/lib/mk/spec/pistachio/timer.mk index 3987ec48d..95bfc547e 100644 --- a/repos/os/lib/mk/spec/pistachio/timer.mk +++ b/repos/os/lib/mk/spec/pistachio/timer.mk @@ -1,6 +1,5 @@ +INC_DIR += $(REP_DIR)/src/drivers/timer/spec/periodic + +SRC_CC += spec/periodic/time_source.cc spec/pistachio/time_source.cc + include $(REP_DIR)/lib/mk/timer.inc - -INC_DIR += $(REP_DIR)/src/drivers/timer/include_periodic - -SRC_CC += platform_timer.cc -vpath platform_timer.cc $(REP_DIR)/src/drivers/timer/spec/pistachio diff --git a/repos/os/lib/mk/spec/sel4_x86_32/timer.mk b/repos/os/lib/mk/spec/sel4_x86_32/timer.mk index 1416a43ba..2bfd262ca 100644 --- a/repos/os/lib/mk/spec/sel4_x86_32/timer.mk +++ b/repos/os/lib/mk/spec/sel4_x86_32/timer.mk @@ -1,3 +1,5 @@ -include $(REP_DIR)/lib/mk/timer.inc +INC_DIR += $(REP_DIR)/src/drivers/timer/spec/pit -INC_DIR += $(REP_DIR)/src/drivers/timer/include_pit +SRC_CC += spec/pit/time_source.cc + +include $(REP_DIR)/lib/mk/timer.inc diff --git a/repos/os/lib/mk/timer.inc b/repos/os/lib/mk/timer.inc index 6edc73322..6d49f9906 100644 --- a/repos/os/lib/mk/timer.inc +++ b/repos/os/lib/mk/timer.inc @@ -1,5 +1,7 @@ -SRC_CC += main.cc -LIBS += base alarm server +SRC_CC += main.cc + +LIBS += base timeout + INC_DIR += $(REP_DIR)/src/drivers/timer/include -vpath main.cc $(REP_DIR)/src/drivers/timer +vpath %.cc $(REP_DIR)/src/drivers/timer diff --git a/repos/os/src/drivers/timer/include/root_component.h b/repos/os/src/drivers/timer/include/root_component.h new file mode 100644 index 000000000..76c84bfe6 --- /dev/null +++ b/repos/os/src/drivers/timer/include/root_component.h @@ -0,0 +1,62 @@ +/* + * \brief Root interface to timer service + * \author Norman Feske + * \author Martin Stein + * \date 2006-08-15 + */ + +/* + * Copyright (C) 2006-2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _ROOT_COMPONENT_H_ +#define _ROOT_COMPONENT_H_ + +/* Genode includes */ +#include + +/* local includes */ +#include +#include + +namespace Timer { class Root_component; } + + +class Timer::Root_component : public Genode::Root_component +{ + private: + + Time_source _time_source; + Genode::Alarm_timeout_scheduler _timeout_scheduler; + + + /******************** + ** Root_component ** + ********************/ + + Session_component *_create_session(const char *args) + { + using namespace Genode; + size_t const ram_quota = + Arg_string::find_arg(args, "ram_quota").ulong_value(0); + + if (ram_quota < sizeof(Session_component)) { + throw Root::Quota_exceeded(); } + + return new (md_alloc()) + Session_component(_timeout_scheduler); + } + + public: + + Root_component(Genode::Entrypoint &ep, Genode::Allocator &md_alloc) + : + Genode::Root_component(&ep.rpc_ep(), &md_alloc), + _time_source(ep), _timeout_scheduler(_time_source) + { } +}; + +#endif /* _ROOT_COMPONENT_H_ */ diff --git a/repos/os/src/drivers/timer/include/session_component.h b/repos/os/src/drivers/timer/include/session_component.h new file mode 100644 index 000000000..e223fd81f --- /dev/null +++ b/repos/os/src/drivers/timer/include/session_component.h @@ -0,0 +1,69 @@ +/* + * \brief Instance of the timer session interface + * \author Norman Feske + * \author Markus Partheymueller + * \author Martin Stein + * \date 2006-08-15 + */ + +/* + * Copyright (C) 2006-2013 Genode Labs GmbH + * Copyright (C) 2012 Intel Corporation + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _SESSION_COMPONENT_ +#define _SESSION_COMPONENT_ + +/* Genode includes */ +#include +#include +#include +#include + +namespace Timer { class Session_component; } + + +class Timer::Session_component : public Genode::Rpc_object, + public Genode::List::Element, + private Genode::Timeout::Handler +{ + private: + + Genode::Timeout _timeout; + Genode::Timeout_scheduler &_timeout_scheduler; + Genode::Signal_context_capability _sigh; + + unsigned long const _init_time_us = _timeout_scheduler.curr_time().value; + + void handle_timeout(Microseconds) { + Genode::Signal_transmitter(_sigh).submit(); } + + public: + + Session_component(Genode::Timeout_scheduler &timeout_scheduler) + : _timeout(timeout_scheduler), _timeout_scheduler(timeout_scheduler) { } + + + /******************** + ** Timer::Session ** + ********************/ + + void trigger_once(unsigned us) override { + _timeout.schedule_one_shot(Microseconds(us), *this); } + + void trigger_periodic(unsigned us) override { + _timeout.schedule_periodic(Microseconds(us), *this); } + + void sigh(Signal_context_capability sigh) override { _sigh = sigh; } + + unsigned long elapsed_ms() const override { + return (_timeout_scheduler.curr_time().value - _init_time_us) / 1000; } + + void msleep(unsigned) override { /* never called at the server side */ } + void usleep(unsigned) override { /* never called at the server side */ } +}; + +#endif /* _SESSION_COMPONENT_ */ diff --git a/repos/os/src/drivers/timer/include/signalled_time_source.h b/repos/os/src/drivers/timer/include/signalled_time_source.h new file mode 100644 index 000000000..ecfcd044f --- /dev/null +++ b/repos/os/src/drivers/timer/include/signalled_time_source.h @@ -0,0 +1,49 @@ +/* + * \brief Time source that handles timeouts via a signal handler + * \author Martin Stein + * \date 2016-11-04 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _SIGNALLED_TIME_SOURCE_H_ +#define _SIGNALLED_TIME_SOURCE_H_ + +/* Genode includes */ +#include +#include +#include + +namespace Genode { class Signalled_time_source; } + + +class Genode::Signalled_time_source : public Time_source +{ + protected: + + using Signal_handler = Genode::Signal_handler; + + Signal_handler _signal_handler; + Timeout_handler *_handler = nullptr; + + void _handle_timeout() + { + if (_handler) { + _handler->handle_timeout(curr_time()); } + } + + public: + + Signalled_time_source(Entrypoint &ep) + : + _signal_handler(ep, *this, + &Signalled_time_source::_handle_timeout) + { } +}; + +#endif /* _SIGNALLED_TIME_SOURCE_H_ */ diff --git a/repos/os/src/drivers/timer/include/threaded_time_source.h b/repos/os/src/drivers/timer/include/threaded_time_source.h new file mode 100644 index 000000000..36196200f --- /dev/null +++ b/repos/os/src/drivers/timer/include/threaded_time_source.h @@ -0,0 +1,89 @@ +/* + * \brief Time source that uses an extra thread for timeout handling + * \author Norman Feske + * \author Martin Stein + * \date 2009-06-16 + */ + +/* + * Copyright (C) 2009-2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _THREADED_TIME_SOURCE_H_ +#define _THREADED_TIME_SOURCE_H_ + +/* Genode inludes */ +#include +#include +#include + +namespace Timer { + + enum { STACK_SIZE = 8 * 1024 * sizeof(Genode::addr_t) }; + + class Threaded_time_source; +} + + +class Timer::Threaded_time_source : public Genode::Time_source, + protected Genode::Thread_deprecated +{ + private: + + struct Irq_dispatcher + { + GENODE_RPC(Rpc_do_dispatch, void, do_dispatch, Microseconds); + GENODE_RPC_INTERFACE(Rpc_do_dispatch); + }; + + struct Irq_dispatcher_component : Genode::Rpc_object + { + Timeout_handler *handler = nullptr; + + + /******************** + ** Irq_dispatcher ** + ********************/ + + void do_dispatch(Microseconds duration) + { + if (handler) { + handler->handle_timeout(Microseconds(duration)); } + } + + } _irq_dispatcher_component; + + Genode::Capability _irq_dispatcher_cap; + + virtual void _wait_for_irq() = 0; + + + /*********************** + ** Thread_deprecated ** + ***********************/ + + void entry() + { + while (true) { + _wait_for_irq(); + _irq_dispatcher_cap.call(curr_time()); + } + } + + public: + + Threaded_time_source(Genode::Entrypoint &ep) + : + Thread_deprecated("threaded_time_source"), + _irq_dispatcher_cap(ep.rpc_ep().manage(&_irq_dispatcher_component)) + { } + + void handler(Timeout_handler &handler) { + _irq_dispatcher_component.handler = &handler; } +}; + +#endif /* _THREADED_TIME_SOURCE_H_ */ diff --git a/repos/os/src/drivers/timer/include/timer_root.h b/repos/os/src/drivers/timer/include/timer_root.h deleted file mode 100644 index 165d41357..000000000 --- a/repos/os/src/drivers/timer/include/timer_root.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * \brief Root interface to timer service - * \author Norman Feske - * \date 2006-08-15 - */ - -/* - * Copyright (C) 2006-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _TIMER_ROOT_H_ -#define _TIMER_ROOT_H_ - -/* Genode includes */ -#include -#include -#include -#include -#include -#include - -/* local includes */ -#include "timer_session_component.h" - - -namespace Timer { class Root_component; } - - -class Timer::Root_component : public Genode::Root_component -{ - private: - - Platform_timer _platform_timer; - Timeout_scheduler _timeout_scheduler; - - protected: - - Session_component *_create_session(const char *args) - { - Genode::size_t ram_quota = Genode::Arg_string::find_arg(args, "ram_quota").ulong_value(0); - - if (ram_quota < sizeof(Session_component)) { - PWRN("Insufficient donated ram_quota (%ld bytes), require %zd bytes", - ram_quota, sizeof(Session_component)); - } - - return new (md_alloc()) - Session_component(_timeout_scheduler); - } - - public: - - /** - * Constructor - * - * The 'cap' argument is not used by the single-threaded server - * variant. - */ - Root_component(Server::Entrypoint &ep, - Genode::Allocator *md_alloc, - Genode::Cap_session *cap) - : - Genode::Root_component(&ep.rpc_ep(), md_alloc), - _timeout_scheduler(&_platform_timer, &ep.rpc_ep()) - { } -}; - -#endif diff --git a/repos/os/src/drivers/timer/include/timer_session_component.h b/repos/os/src/drivers/timer/include/timer_session_component.h deleted file mode 100644 index 26733c25c..000000000 --- a/repos/os/src/drivers/timer/include/timer_session_component.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * \brief Instance of the timer session interface - * \author Norman Feske - * \author Markus Partheymueller - * \date 2006-08-15 - */ - -/* - * Copyright (C) 2006-2013 Genode Labs GmbH - * Copyright (C) 2012 Intel Corporation - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _TIMER_SESSION_COMPONENT_ -#define _TIMER_SESSION_COMPONENT_ - -/* Genode includes */ -#include -#include -#include -#include - -/* local includes */ -#include "platform_timer.h" - - -namespace Timer { - - enum { STACK_SIZE = 32*1024 }; - - struct Irq_dispatcher; - class Irq_dispatcher_component; - class Wake_up_alarm; - class Timeout_scheduler; - class Session_component; -} - - -struct Timer::Irq_dispatcher -{ - GENODE_RPC(Rpc_do_dispatch, void, do_dispatch); - GENODE_RPC_INTERFACE(Rpc_do_dispatch); -}; - - -/** - * Timer interrupt handler - * - * This class represents a RPC object that gets locally called for each - * timer interrupt. It is managed by the same entrypoint as all timer - * client components. Because the 'do_dispatch' function is executed in - * the same thread context as the dispatch functions of client requests, - * we are able to answer those requests from here (by calling the - * 'handle()' function of the alarm scheduler). - */ -class Timer::Irq_dispatcher_component : public Genode::Rpc_object -{ - private: - - Genode::Alarm_scheduler *_alarm_scheduler; - Platform_timer *_platform_timer; - - public: - - /** - * Constructor - */ - Irq_dispatcher_component(Genode::Alarm_scheduler *as, - Platform_timer *pt) - : _alarm_scheduler(as), _platform_timer(pt) { } - - - /****************************** - ** Irq_dispatcher interface ** - ******************************/ - - void do_dispatch() - { - using namespace Genode; - - Alarm::Time now = _platform_timer->curr_time(); - Alarm::Time sleep_time; - - /* trigger timeout alarms */ - _alarm_scheduler->handle(now); - - /* determine duration for next one-shot timer event */ - Alarm::Time deadline; - if (_alarm_scheduler->next_deadline(&deadline)) - sleep_time = deadline - now; - else - sleep_time = _platform_timer->max_timeout(); - - if (sleep_time == 0) - sleep_time = 1; - - _platform_timer->schedule_timeout(sleep_time); - } -}; - - -/** - * Alarm for answering an oneshot timeout request - */ -class Timer::Wake_up_alarm : public Genode::Alarm -{ - private: - - Genode::Signal_context_capability _sigh; - bool _periodic; - - public: - - Wake_up_alarm() : _periodic(false) { } - - void sigh(Genode::Signal_context_capability sigh) { _sigh = sigh; } - void periodic(bool periodic) { _periodic = periodic; } - bool periodic() { return _periodic; } - - - /********************* - ** Alarm interface ** - *********************/ - - /** - * Dispatch a wakeup alarm - * - * This function gets called by the 'Alarm_scheduler' thread. - */ - bool on_alarm (unsigned cnt) override - { - Genode::Signal_transmitter(_sigh).submit(cnt); - - return _periodic; - } -}; - - -class Timer::Timeout_scheduler : public Genode::Alarm_scheduler, - Genode::Thread_deprecated -{ - private: - - typedef Genode::Capability - Irq_dispatcher_capability; - - Platform_timer *_platform_timer; - Irq_dispatcher_component _irq_dispatcher_component; - Irq_dispatcher_capability _irq_dispatcher_cap; - - /** - * Timer-interrupt thread - * - * This thread blocks for the timer interrupt. For each occuring - * interrupt, it performs an local RPC call to the server - * activation, which, in turn, processes the scheduled timeouts and - * reprograms the platform timer. - */ - void entry() - { - while (true) { - - _platform_timer->wait_for_timeout(this); - - /* - * Call timer irq handler to trigger timeout alarms and - * reprogram the platform timer. - */ - _irq_dispatcher_cap.call(); - } - } - - public: - - /** - * Constructor - */ - Timeout_scheduler(Platform_timer *pt, Genode::Rpc_entrypoint *ep) - : - Thread_deprecated("timeout_scheduler"), - _platform_timer(pt), - _irq_dispatcher_component(this, pt), - _irq_dispatcher_cap(ep->manage(&_irq_dispatcher_component)) - { - _platform_timer->schedule_timeout(0); - start(); - } - - /** - * Called from the '_trigger' function executed by the server activation - */ - void schedule_timeout(Wake_up_alarm *alarm, Genode::Alarm::Time timeout) - { - Genode::Alarm::Time now = _platform_timer->curr_time(); - if (alarm->periodic()) { - handle(now); /* update '_now' in 'Alarm_scheduler' */ - schedule(alarm, timeout); - } else schedule_absolute(alarm, now + timeout); - - /* interrupt current 'wait_for_timeout' */ - if (head_timeout(alarm)) - _platform_timer->schedule_timeout(0); - } - - unsigned long curr_time() const - { - return _platform_timer->curr_time(); - } -}; - - -/** - * Timer session - */ -class Timer::Session_component : public Genode::Rpc_object, - public Genode::List::Element -{ - private: - - Timeout_scheduler &_timeout_scheduler; - Wake_up_alarm _wake_up_alarm; - unsigned long const _initial_time; - - void _trigger(unsigned us, bool periodic) - { - _wake_up_alarm.periodic(periodic); - _timeout_scheduler.schedule_timeout(&_wake_up_alarm, us); - } - - public: - - /** - * Constructor - */ - Session_component(Timeout_scheduler &ts) - : - _timeout_scheduler(ts), - _initial_time(_timeout_scheduler.curr_time()) - { } - - /** - * Destructor - */ - ~Session_component() - { - _timeout_scheduler.discard(&_wake_up_alarm); - } - - - /***************************** - ** Timer session interface ** - *****************************/ - - void trigger_once(unsigned us) - { - _trigger(us, false); - } - - void trigger_periodic(unsigned us) - { - _trigger(us, true); - } - - void sigh(Signal_context_capability sigh) - { - _wake_up_alarm.sigh(sigh); - } - - unsigned long elapsed_ms() const - { - unsigned long const now = _timeout_scheduler.curr_time(); - return (now - _initial_time) / 1000; - } - - void msleep(unsigned) { /* never called at the server side */ } - void usleep(unsigned) { /* never called at the server side */ } -}; - -#endif diff --git a/repos/os/src/drivers/timer/include_periodic/platform_timer.h b/repos/os/src/drivers/timer/include_periodic/platform_timer.h deleted file mode 100644 index e3726ec24..000000000 --- a/repos/os/src/drivers/timer/include_periodic/platform_timer.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * \brief Platform timer based on spinning usleep - * \author Norman Feske - * \date 2009-06-16 - */ - -/* - * Copyright (C) 2009-2015 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _PLATFORM_TIMER_H_ -#define _PLATFORM_TIMER_H_ - -/* Genode inludes */ -#include -#include - - -class Platform_timer -{ - private: - - Genode::Lock mutable _lock; /* for protecting '_next_timeout_usec' */ - unsigned long _next_timeout_usec; /* timeout of current sleep */ - unsigned long _curr_time_usec; /* accumulated sleep time */ - - /** - * Platform-specific sleep implementation - */ - void _usleep(unsigned long usecs); - - public: - - /** - * Constructor - */ - Platform_timer() : _next_timeout_usec(max_timeout()), _curr_time_usec(0) { } - - /** - * Set next relative timeout - */ - void schedule_timeout(unsigned long timeout_usec) - { - Genode::Lock::Guard lock_guard(_lock); - _next_timeout_usec = timeout_usec; - } - - /** - * Return maximum supported timeout in microseconds - */ - unsigned long max_timeout(); - - /** - * Get current time in microseconds - */ - unsigned long curr_time() const; - - /** - * Block until the scheduled timeout triggers - */ - void wait_for_timeout(Genode::Thread *blocking_thread) - { - enum { SLEEP_GRANULARITY_USEC = 1000UL }; - - unsigned long last_time = curr_time(); - _lock.lock(); - while (_next_timeout_usec) { - _lock.unlock(); - - try { _usleep(SLEEP_GRANULARITY_USEC); } - catch (Genode::Blocking_canceled) { } - - unsigned long now_time = curr_time(); - unsigned long sleep_duration = now_time - last_time; - last_time = now_time; - - _lock.lock(); - - if (_next_timeout_usec >= sleep_duration) - _next_timeout_usec -= sleep_duration; - else - break; - } - _lock.unlock(); - } -}; - -#endif /* _PLATFORM_TIMER_H_ */ diff --git a/repos/os/src/drivers/timer/include_pit/platform_timer.h b/repos/os/src/drivers/timer/include_pit/platform_timer.h deleted file mode 100644 index 38389f9d4..000000000 --- a/repos/os/src/drivers/timer/include_pit/platform_timer.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * \brief Platform timer based on the Programmable Interval Timer (PIT) - * \author Norman Feske - * \date 2009-06-16 - */ - -/* - * Copyright (C) 2009-2015 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _PLATFORM_TIMER_H_ -#define _PLATFORM_TIMER_H_ - -/* Genode includes */ -#include -#include -#include - -class Platform_timer -{ - private: - - enum { - PIT_TICKS_PER_SECOND = 1193182, - PIT_TICKS_PER_MSEC = PIT_TICKS_PER_SECOND/1000, - PIT_MAX_COUNT = 65535, - PIT_DATA_PORT_0 = 0x40, /* data port for PIT channel 0, - connected to the PIC */ - PIT_CMD_PORT = 0x43, /* PIT command port */ - - PIT_MAX_USEC = (PIT_MAX_COUNT*1000)/(PIT_TICKS_PER_MSEC) - }; - - enum { - IRQ_PIT = 0, /* timer interrupt at the PIC */ - }; - - /** - * Bit definitions for accessing the PIT command port - */ - enum { - PIT_CMD_SELECT_CHANNEL_0 = 0 << 6, - PIT_CMD_ACCESS_LO = 1 << 4, - PIT_CMD_ACCESS_LO_HI = 3 << 4, - PIT_CMD_MODE_IRQ = 0 << 1, - PIT_CMD_MODE_RATE = 2 << 1, - - PIT_CMD_READ_BACK = 3 << 6, - PIT_CMD_RB_COUNT = 0 << 5, - PIT_CMD_RB_STATUS = 0 << 4, - PIT_CMD_RB_CHANNEL_0 = 1 << 1, - }; - - /** - * Bit definitions of the PIT status byte - */ - enum { - PIT_STAT_INT_LINE = 1 << 7, - }; - - Genode::Io_port_connection _io_port; - Genode::Irq_connection _timer_irq; - unsigned long mutable _curr_time_usec; - Genode::uint16_t mutable _counter_init_value; - bool mutable _handled_wrap; - Genode::Signal_receiver _irq_rec; - Genode::Signal_context _irq_ctx; - - /** - * Set PIT counter value - */ - void _set_counter(Genode::uint16_t value) - { - _handled_wrap = false; - _io_port.outb(PIT_DATA_PORT_0, value & 0xff); - _io_port.outb(PIT_DATA_PORT_0, (value >> 8) & 0xff); - } - - /** - * Read current PIT counter value - */ - Genode::uint16_t _read_counter(bool *wrapped) - { - /* read-back count and status of counter 0 */ - _io_port.outb(PIT_CMD_PORT, PIT_CMD_READ_BACK | - PIT_CMD_RB_COUNT | PIT_CMD_RB_STATUS | PIT_CMD_RB_CHANNEL_0); - - /* read status byte from latch register */ - Genode::uint8_t status = _io_port.inb(PIT_DATA_PORT_0); - - /* read low and high bytes from latch register */ - Genode::uint16_t lo = _io_port.inb(PIT_DATA_PORT_0); - Genode::uint16_t hi = _io_port.inb(PIT_DATA_PORT_0); - - *wrapped = status & PIT_STAT_INT_LINE ? true : false; - return (hi << 8) | lo; - } - - public: - - /** - * Constructor - */ - Platform_timer() - : - _io_port(PIT_DATA_PORT_0, PIT_CMD_PORT - PIT_DATA_PORT_0 + 1), - _timer_irq(IRQ_PIT), - _curr_time_usec(0), - _counter_init_value(0), - _handled_wrap(false) - { - /* operate PIT in one-shot mode */ - _io_port.outb(PIT_CMD_PORT, PIT_CMD_SELECT_CHANNEL_0 | - PIT_CMD_ACCESS_LO_HI | PIT_CMD_MODE_IRQ); - - _timer_irq.sigh(_irq_rec.manage(&_irq_ctx)); - _timer_irq.ack_irq(); - } - - ~Platform_timer() { _irq_rec.dissolve(&_irq_ctx); } - - /** - * Return current time-counter value in microseconds - * - * This function has to be executed regularly, - * at least all max_timeout() usecs. - */ - unsigned long curr_time() const - { - Genode::uint32_t passed_ticks; - - /* - * Read PIT count and status - * - * Reading the PIT registers via port I/O is a non-const operation. - * Since 'curr_time' is declared as const, however, we need to - * explicitly override the const-ness of the 'this' pointer. - */ - bool wrapped; - Genode::uint16_t const curr_counter = const_cast(this)->_read_counter(&wrapped); - - /* determine the time since we looked at the counter */ - if (wrapped && !_handled_wrap) { - passed_ticks = _counter_init_value; - /* the counter really wrapped around */ - if (curr_counter) - passed_ticks += PIT_MAX_COUNT + 1 - curr_counter; - - _handled_wrap = true; - } else { - if (_counter_init_value) - passed_ticks = _counter_init_value - curr_counter; - else - passed_ticks = PIT_MAX_COUNT + 1 - curr_counter; - } - - _curr_time_usec += (passed_ticks*1000)/PIT_TICKS_PER_MSEC; - - /* use current counter as the reference for the next update */ - _counter_init_value = curr_counter; - - return _curr_time_usec; - } - - /** - * Return maximum timeout as supported by the platform - */ - unsigned long max_timeout() { return PIT_MAX_USEC; } - - /** - * Schedule next timeout - * - * \param timeout_usec timeout in microseconds - * - * The maximum value for 'timeout_ms' is 54924 microseconds. If - * specifying a higher timeout, this maximum value will be scheduled. - */ - void schedule_timeout(unsigned long timeout_usec) - { - /* limit timer-interrupt rate */ - enum { MAX_TIMER_IRQS_PER_SECOND = 4*1000 }; - if (timeout_usec < 1000*1000/MAX_TIMER_IRQS_PER_SECOND) - timeout_usec = 1000*1000/MAX_TIMER_IRQS_PER_SECOND; - - if (timeout_usec > max_timeout()) - timeout_usec = max_timeout(); - - _counter_init_value = (PIT_TICKS_PER_MSEC * timeout_usec)/1000; - _set_counter(_counter_init_value); - } - - /** - * Block for the next scheduled timeout - */ - void wait_for_timeout(Genode::Thread *blocking_thread) - { - _irq_rec.wait_for_signal(); - _timer_irq.ack_irq(); - } -}; - -#endif /* _PLATFORM_TIMER_H_ */ diff --git a/repos/os/src/drivers/timer/main.cc b/repos/os/src/drivers/timer/main.cc index a66fa1710..e6e32d3b1 100644 --- a/repos/os/src/drivers/timer/main.cc +++ b/repos/os/src/drivers/timer/main.cc @@ -1,6 +1,7 @@ /* - * \brief Timer service + * \brief Provides the Timer service to multiple clients * \author Norman Feske + * \author Martin Stein * \date 2006-08-15 */ @@ -12,45 +13,35 @@ */ /* Genode includes */ -#include -#include #include -#include -#include +#include /* local includes */ -#include "timer_root.h" +#include using namespace Genode; -using namespace Timer; -struct Main +class Main { - Server::Entrypoint &ep; - Sliced_heap sliced_heap; - Timer::Root_component root; + private: - Main(Server::Entrypoint &ep) - : - ep(ep), - sliced_heap(Genode::env()->ram_session(), Genode::env()->rm_session()), - root(ep, &sliced_heap, 0) - { - /* - * Announce timer service at our parent. - */ - env()->parent()->announce(ep.manage(root)); - } + Sliced_heap _sliced_heap; + Timer::Root_component _root; + + public: + + Main(Env &env) : _sliced_heap(env.ram(), env.rm()), + _root(env.ep(), _sliced_heap) + { + env.parent().announce(env.ep().manage(_root)); + } }; -/************ - ** Server ** - ************/ +/*************** + ** Component ** + ***************/ -namespace Server { - char const *name() { return "timer_drv_ep"; } - size_t stack_size() { return 2048*sizeof(long); } - void construct(Entrypoint &ep) { static Main server(ep); } -} +size_t Component::stack_size() { return 2 * 1024 * sizeof(addr_t); } +void Component::construct(Env &env) { static Main main(env); } diff --git a/repos/os/src/drivers/timer/spec/fiasco/platform_timer.cc b/repos/os/src/drivers/timer/spec/fiasco/time_source.cc similarity index 73% rename from repos/os/src/drivers/timer/spec/fiasco/platform_timer.cc rename to repos/os/src/drivers/timer/spec/fiasco/time_source.cc index 795858514..4e70c9870 100644 --- a/repos/os/src/drivers/timer/spec/fiasco/platform_timer.cc +++ b/repos/os/src/drivers/timer/spec/fiasco/time_source.cc @@ -1,7 +1,8 @@ /* - * \brief Fiasco-specific sleep implementation + * \brief Time source that uses sleeping by the means of the kernel * \author Christian Helmuth * \author Norman Feske + * \author Martin Stein * \date 2006-08-30 */ @@ -14,7 +15,6 @@ /* Genode includes */ #include -#include #include /* Fiasco includes */ @@ -36,9 +36,10 @@ namespace Fiasco { #endif /* L4_SYS_KIP_H__ */ /* local includes */ -#include "timer_session_component.h" +#include using namespace Fiasco; +using Microseconds = Genode::Time_source::Microseconds; static l4_timeout_s mus_to_timeout(unsigned long mus) @@ -50,42 +51,36 @@ static l4_timeout_s mus_to_timeout(unsigned long mus) long e = Genode::log2(mus) - 7; unsigned long m; - if (e < 0) e = 0; m = mus / (1UL << e); /* check corner case */ if ((e > 31 ) || (m > 1023)) { - PWRN("invalid timeout %ld, using max. values\n", mus); + Genode::warning("invalid timeout ", mus, ", using max. values"); e = 0; m = 1023; } - return l4_timeout_rel(m, e); } -unsigned long Platform_timer::max_timeout() +Microseconds Timer::Time_source::max_timeout() const { Genode::Lock::Guard lock_guard(_lock); - - return 1000*1000*100; + return Microseconds(1000 * 1000 * 100); } -unsigned long Platform_timer::curr_time() const +Microseconds Timer::Time_source::curr_time() const { Genode::Lock::Guard lock_guard(_lock); - - static Genode::Attached_rom_dataspace kip_ds("l4v2_kip"); + static Genode::Attached_rom_dataspace kip_ds("l4v2_kip"); static Fiasco::l4_kernel_info_t * const kip = kip_ds.local_addr(); - return kip->clock; + return Microseconds(kip->clock); } -void Platform_timer::_usleep(unsigned long usecs) -{ - l4_ipc_sleep(l4_timeout(L4_IPC_TIMEOUT_NEVER, mus_to_timeout(usecs))); -} +void Timer::Time_source::_usleep(unsigned long usecs) { + l4_ipc_sleep(l4_timeout(L4_IPC_TIMEOUT_NEVER, mus_to_timeout(usecs))); } diff --git a/repos/os/src/drivers/timer/spec/hw/platform_timer.h b/repos/os/src/drivers/timer/spec/hw/platform_timer.h deleted file mode 100644 index aef000f2a..000000000 --- a/repos/os/src/drivers/timer/spec/hw/platform_timer.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * \brief Platform timer specific for base-hw - * \author Martin Stein - * \date 2012-05-03 - */ - -/* - * Copyright (C) 2012-2015 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _OS__SRC__DRIVERS__TIMER__HW__PLATFORM_TIMER_H_ -#define _OS__SRC__DRIVERS__TIMER__HW__PLATFORM_TIMER_H_ - -/* Genode includes */ -#include -#include - -/* base-hw includes */ -#include - -/** - * Platform timer specific for base-hw - */ -class Platform_timer -{ - private: - - using time_t = Kernel::time_t; - - Genode::Signal_receiver _sigrec; - Genode::Signal_context _sigctx; - Kernel::capid_t const _sigid; - unsigned long mutable _curr_time_us; - Genode::Lock mutable _curr_time_us_lock; - unsigned long mutable _last_timeout_age_us; - time_t const _max_timeout_us; - - /** - * Return kernel capability selector of Genode capability - * - * This function is normally framework-internal and defined in - * 'base/internal/capability_space.h'. - */ - static inline Kernel::capid_t _capid(Genode::Native_capability const &cap) - { - Genode::addr_t const index = (Genode::addr_t)cap.data(); - return index; - } - - public: - - Platform_timer() - : - _sigid(_capid(_sigrec.manage(&_sigctx))), - _curr_time_us(0), _last_timeout_age_us(0), - _max_timeout_us(Kernel::timeout_max_us()) - { - Genode::log("maximum timeout ", _max_timeout_us, " us"); - if (max_timeout() < min_timeout()) { - Genode::error("minimum timeout greater then maximum timeout"); - throw Genode::Exception(); - } - } - - ~Platform_timer() { _sigrec.dissolve(&_sigctx); } - - /** - * Refresh and return time in microseconds - * - * This function has to be executed regulary, at least all - * max_timeout() us. - */ - unsigned long curr_time() const - { - Genode::Lock::Guard lock(_curr_time_us_lock); - time_t const timeout_age_us = Kernel::timeout_age_us(); - if (timeout_age_us > _last_timeout_age_us) { - - /* increment time by the difference since the last update */ - _curr_time_us += timeout_age_us - _last_timeout_age_us; - _last_timeout_age_us = timeout_age_us; - } - return _curr_time_us; - } - - /** - * Return maximum timeout in microseconds - */ - time_t max_timeout() const { return _max_timeout_us; } - - /** - * Return minimum timeout in microseconds - */ - static time_t min_timeout() { return 1000; } - - /** - * Schedule next timeout, bad timeouts are adapted - * - * \param timeout_us Timeout in microseconds - */ - void schedule_timeout(time_t timeout_us) - { - Genode::Lock::Guard lock(_curr_time_us_lock); - if (timeout_us < min_timeout()) { timeout_us = min_timeout(); } - if (timeout_us > max_timeout()) { timeout_us = max_timeout(); } - - /* - * Once the timer runs, one can wait for its signal and update our - * timeout counter through 'curr_time()' (We rely on the fact that - * this is done at least one time in every max-timeout period) - */ - _last_timeout_age_us = 0; - Kernel::timeout(timeout_us, _sigid); - } - - /** - * Await the lastly scheduled timeout - */ - void wait_for_timeout(Genode::Thread *) { _sigrec.wait_for_signal(); } -}; - -#endif /* _OS__SRC__DRIVERS__TIMER__HW__PLATFORM_TIMER_H_ */ diff --git a/repos/os/src/drivers/timer/spec/hw/time_source.cc b/repos/os/src/drivers/timer/spec/hw/time_source.cc new file mode 100644 index 000000000..2ed8751d2 --- /dev/null +++ b/repos/os/src/drivers/timer/spec/hw/time_source.cc @@ -0,0 +1,69 @@ +/* + * \brief Time source that uses the timeout syscalls of the HW kernel + * \author Martin Stein + * \date 2012-05-03 + */ + +/* + * Copyright (C) 2012-2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include +#include +#include + +/* local includes */ +#include + +/* base-hw includes */ +#include + +using namespace Genode; +using Microseconds = Genode::Time_source::Microseconds; + +enum { MIN_TIMEOUT_US = 1000 }; + + +Timer::Time_source::Time_source(Entrypoint &ep) +: + Signalled_time_source(ep), + _max_timeout_us(Kernel::timeout_max_us()) +{ + if (_max_timeout_us < MIN_TIMEOUT_US) { + error("minimum timeout greater then maximum timeout"); + throw Genode::Exception(); + } +} + + +void Timer::Time_source::schedule_timeout(Microseconds duration, + Timeout_handler &handler) +{ + unsigned long duration_us = duration.value; + if (duration_us < MIN_TIMEOUT_US) { + duration_us = MIN_TIMEOUT_US; } + + if (duration_us > max_timeout().value) { + duration_us = max_timeout().value; } + + _handler = &handler; + _last_timeout_age_us = 0; + Kernel::timeout(duration_us, (addr_t)_signal_handler.data()); +} + + +Microseconds Timer::Time_source::curr_time() const +{ + unsigned long const timeout_age_us = Kernel::timeout_age_us(); + if (timeout_age_us > _last_timeout_age_us) { + + /* increment time by the difference since the last update */ + _curr_time_us += timeout_age_us - _last_timeout_age_us; + _last_timeout_age_us = timeout_age_us; + } + return Microseconds(_curr_time_us); +} diff --git a/repos/os/src/drivers/timer/spec/hw/time_source.h b/repos/os/src/drivers/timer/spec/hw/time_source.h new file mode 100644 index 000000000..60c554c76 --- /dev/null +++ b/repos/os/src/drivers/timer/spec/hw/time_source.h @@ -0,0 +1,46 @@ +/* + * \brief Time source that uses the timeout syscalls of the HW kernel + * \author Martin Stein + * \date 2012-05-03 + */ + +/* + * Copyright (C) 2012-2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _TIME_SOURCE_H_ +#define _TIME_SOURCE_H_ + +/* local includes */ +#include + +namespace Timer { class Time_source; } + + +class Timer::Time_source : public Genode::Signalled_time_source +{ + private: + + unsigned long mutable _curr_time_us = 0; + unsigned long mutable _last_timeout_age_us = 0; + unsigned long const _max_timeout_us; + + public: + + Time_source(Genode::Entrypoint &ep); + + + /************************* + ** Genode::Time_source ** + *************************/ + + Microseconds curr_time() const override; + void schedule_timeout(Microseconds duration, Timeout_handler &handler) override; + Microseconds max_timeout() const override { + return Microseconds(_max_timeout_us); }; +}; + +#endif /* _TIME_SOURCE_H_ */ diff --git a/repos/os/src/drivers/timer/spec/linux/platform_timer.cc b/repos/os/src/drivers/timer/spec/linux/platform_timer.cc deleted file mode 100644 index 2219536a7..000000000 --- a/repos/os/src/drivers/timer/spec/linux/platform_timer.cc +++ /dev/null @@ -1,53 +0,0 @@ -/* - * \brief Linux-specific sleep implementation - * \author Norman Feske - * \date 2006-08-15 - */ - -/* - * Copyright (C) 2006-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -/* Linux syscall bindings */ -#include - -/* local includes */ -#include "timer_session_component.h" - -/* Linux includes */ -#include -#include - -inline int lx_gettimeofday(struct timeval *tv, struct timeval *tz) -{ - return lx_syscall(SYS_gettimeofday, tv, tz); -} - - -unsigned long Platform_timer::max_timeout() -{ - Genode::Lock::Guard lock_guard(_lock); - return 1000*1000; -} - - -unsigned long Platform_timer::curr_time() const -{ - struct timeval tv; - lx_gettimeofday(&tv, 0); - return tv.tv_sec*1000*1000 + tv.tv_usec; -} - - -void Platform_timer::_usleep(unsigned long usecs) -{ - struct timespec ts; - ts.tv_sec = usecs / (1000*1000); - ts.tv_nsec = (usecs % (1000*1000)) * 1000; - - if (lx_nanosleep(&ts, &ts) != 0) - throw Genode::Blocking_canceled(); -} diff --git a/repos/os/src/drivers/timer/spec/linux/time_source.cc b/repos/os/src/drivers/timer/spec/linux/time_source.cc new file mode 100644 index 000000000..caeaea403 --- /dev/null +++ b/repos/os/src/drivers/timer/spec/linux/time_source.cc @@ -0,0 +1,53 @@ +/* + * \brief Time source that uses sleeping by the means of the kernel + * \author Norman Feske + * \author Martin Stein + * \date 2006-08-15 + */ + +/* + * Copyright (C) 2006-2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Linux includes */ +#include +#include + +/* local includes */ +#include + +using namespace Genode; +using Microseconds = Genode::Time_source::Microseconds; + + +inline int lx_gettimeofday(struct timeval *tv, struct timeval *tz) { + return lx_syscall(SYS_gettimeofday, tv, tz); } + + +Microseconds Timer::Time_source::max_timeout() const +{ + Lock::Guard lock_guard(_lock); + return Microseconds(1000 * 1000); +} + + +Microseconds Timer::Time_source::curr_time() const +{ + struct timeval tv; + lx_gettimeofday(&tv, 0); + return Microseconds(tv.tv_sec * 1000 * 1000 + tv.tv_usec); +} + + +void Timer::Time_source::_usleep(unsigned long us) +{ + struct timespec ts; + ts.tv_sec = us / (1000 * 1000); + ts.tv_nsec = (us % (1000 * 1000)) * 1000; + + if (lx_nanosleep(&ts, &ts) != 0) + throw Blocking_canceled(); +} diff --git a/repos/os/src/drivers/timer/spec/nova/platform_timer.h b/repos/os/src/drivers/timer/spec/nova/platform_timer.h deleted file mode 100644 index 7c17f39b0..000000000 --- a/repos/os/src/drivers/timer/spec/nova/platform_timer.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * \brief Platform timer using Nova timed semaphore down - * \author Alexander Boettcher - * \date 2014-06-24 - */ - -/* - * Copyright (C) 2014-2015 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _PLATFORM_TIMER_H_ -#define _PLATFORM_TIMER_H_ - -/* Genode includes */ -#include -#include -#include - -/* NOVA includes */ -#include - -class Platform_timer -{ - private: - - Genode::addr_t _sem; - unsigned long _timeout; - Genode::Trace::Timestamp _tsc_start; - unsigned long _tsc_khz; - - /* 1 / ((us / (1000 * 1000)) * (tsc_khz * 1000)) */ - enum { TSC_FACTOR = 1000ULL }; - - /** - * Convenience function to calculate time in us value out of tsc - */ - inline unsigned long _time_in_us(unsigned long long tsc, - bool sub_tsc_start = true) const - { - if (sub_tsc_start) - return (tsc - _tsc_start) / (_tsc_khz / TSC_FACTOR); - - return (tsc) / (_tsc_khz / TSC_FACTOR); - } - - public: - - /** - * Constructor - */ - Platform_timer() - : - _sem(~0UL), _timeout(0), - _tsc_start(Genode::Trace::timestamp()) - { - /* read out the tsc frequenzy once */ - Genode::Attached_rom_dataspace _ds("hypervisor_info_page"); - Nova::Hip * const hip = _ds.local_addr(); - _tsc_khz = hip->tsc_freq; - } - - - /** - * Return current time-counter value in microseconds - */ - unsigned long curr_time() const - { - return _time_in_us(Genode::Trace::timestamp()); - } - - /** - * Return maximum timeout as supported by the platform - */ - unsigned long max_timeout() { return _time_in_us(~0UL); } - - /** - * Schedule next timeout - * - * \param timeout_usec timeout in microseconds - */ - void schedule_timeout(unsigned long timeout_usec) - { - using namespace Genode; - - /* check whether to cancel last timeout */ - if (timeout_usec == 0 && _sem != ~0UL) { - uint8_t res = Nova::sm_ctrl(_sem, Nova::SEMAPHORE_UP); - if (res != Nova::NOVA_OK) - nova_die(); - } - - /* remember timeout to be set during wait_for_timeout call */ - _timeout = timeout_usec; - } - - /** - * Block for the next scheduled timeout - */ - void wait_for_timeout(Genode::Thread *blocking_thread) - { - using namespace Genode; - using namespace Nova; - - if (_sem == ~0UL) - _sem = blocking_thread->native_thread().exc_pt_sel + SM_SEL_EC; - - addr_t sem = _sem; - - /* calculate absolute timeout */ - Trace::Timestamp now = Trace::timestamp(); - Trace::Timestamp us_64 = _timeout; - - if (_timeout == max_timeout()) { - /* tsc_absolute == 0 means blocking without timeout */ - Genode::uint8_t res = sm_ctrl(sem, SEMAPHORE_DOWN, 0); - if (res != Nova::NOVA_OK && res != Nova::NOVA_TIMEOUT) - nova_die(); - return; - } - - /* block until timeout fires or it gets canceled */ - unsigned long long tsc_absolute = now + us_64 * (_tsc_khz / TSC_FACTOR); - Genode::uint8_t res = sm_ctrl(sem, SEMAPHORE_DOWN, tsc_absolute); - if (res != Nova::NOVA_OK && res != Nova::NOVA_TIMEOUT) - nova_die(); - } -}; - -#endif /* _PLATFORM_TIMER_H_ */ diff --git a/repos/os/src/drivers/timer/spec/nova/time_source.cc b/repos/os/src/drivers/timer/spec/nova/time_source.cc new file mode 100644 index 000000000..a701b9390 --- /dev/null +++ b/repos/os/src/drivers/timer/spec/nova/time_source.cc @@ -0,0 +1,81 @@ +/* + * \brief Time source using Nova timed semaphore down + * \author Alexander Boettcher + * \author Martin Stein + * \date 2014-06-24 + */ + +/* + * Copyright (C) 2014-2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include + +/* NOVA includes */ +#include + +/* local includes */ +#include + +using namespace Genode; +using namespace Nova; +using Microseconds = Genode::Time_source::Microseconds; + + +Timer::Time_source::Time_source(Entrypoint &ep) : Threaded_time_source(ep) +{ + /* read out the tsc frequenzy once */ + Attached_rom_dataspace _ds("hypervisor_info_page"); + Nova::Hip * const hip = _ds.local_addr(); + _tsc_khz = hip->tsc_freq; + start(); +} + + +void Timer::Time_source::schedule_timeout(Microseconds duration, + Timeout_handler &handler) +{ + Threaded_time_source::handler(handler); + + /* check whether to cancel last timeout */ + if (duration.value == 0 && _sem != ~0UL) { + uint8_t res = Nova::sm_ctrl(_sem, Nova::SEMAPHORE_UP); + if (res != Nova::NOVA_OK) + nova_die(); + } + /* remember timeout to be set during wait_for_timeout call */ + _timeout_us = duration.value; +} + + +void Timer::Time_source::_wait_for_irq() +{ + if (_sem == ~0UL) { + _sem = Thread::native_thread().exc_pt_sel + SM_SEL_EC; } + + addr_t sem = _sem; + + /* calculate absolute timeout */ + Trace::Timestamp now = Trace::timestamp(); + Trace::Timestamp us_64 = _timeout_us; + + if (_timeout_us == max_timeout().value) { + + /* tsc_absolute == 0 means blocking without timeout */ + uint8_t res = sm_ctrl(sem, SEMAPHORE_DOWN, 0); + if (res != Nova::NOVA_OK && res != Nova::NOVA_TIMEOUT) { + nova_die(); } + + } else { + + /* block until timeout fires or it gets canceled */ + unsigned long long tsc_absolute = now + us_64 * (_tsc_khz / TSC_FACTOR); + uint8_t res = sm_ctrl(sem, SEMAPHORE_DOWN, tsc_absolute); + if (res != Nova::NOVA_OK && res != Nova::NOVA_TIMEOUT) { + nova_die(); } + } +} diff --git a/repos/os/src/drivers/timer/spec/nova/time_source.h b/repos/os/src/drivers/timer/spec/nova/time_source.h new file mode 100644 index 000000000..3c59255d0 --- /dev/null +++ b/repos/os/src/drivers/timer/spec/nova/time_source.h @@ -0,0 +1,71 @@ +/* + * \brief Time source using Nova timed semaphore down + * \author Alexander Boettcher + * \author Martin Stein + * \date 2014-06-24 + */ + +/* + * Copyright (C) 2014-2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _TIME_SOURCE_H_ +#define _TIME_SOURCE_H_ + +/* Genode includes */ +#include + +/* local includes */ +#include + +namespace Timer { class Time_source; } + + +class Timer::Time_source : public Threaded_time_source +{ + private: + + Genode::addr_t _sem = ~0UL; + unsigned long _timeout_us = 0; + Genode::Trace::Timestamp _tsc_start = Genode::Trace::timestamp(); + unsigned long _tsc_khz; + + /* 1 / ((us / (1000 * 1000)) * (tsc_khz * 1000)) */ + enum { TSC_FACTOR = 1000ULL }; + + inline Microseconds _tsc_to_us(unsigned long long tsc, + bool sub_tsc_start = true) const + { + if (sub_tsc_start) { + return Microseconds((tsc - _tsc_start) / + (_tsc_khz / TSC_FACTOR)); + } + return Microseconds((tsc) / (_tsc_khz / TSC_FACTOR)); + } + + + /************************** + ** Threaded_time_source ** + **************************/ + + void _wait_for_irq(); + + public: + + Time_source(Genode::Entrypoint &ep); + + + /************************* + ** Genode::Time_source ** + *************************/ + + Microseconds max_timeout() const override { return _tsc_to_us(~0UL); } + void schedule_timeout(Microseconds duration, Timeout_handler &handler) override; + Microseconds curr_time() const override { + return _tsc_to_us(Genode::Trace::timestamp()); } +}; + +#endif /* _TIME_SOURCE_H_ */ diff --git a/repos/os/src/drivers/timer/spec/periodic/time_source.cc b/repos/os/src/drivers/timer/spec/periodic/time_source.cc new file mode 100644 index 000000000..58872bec5 --- /dev/null +++ b/repos/os/src/drivers/timer/spec/periodic/time_source.cc @@ -0,0 +1,52 @@ +/* + * \brief Time source that uses sleeping by the means of the kernel + * \author Norman Feske + * \author Martin Stein + * \date 2009-06-16 + */ + +/* + * Copyright (C) 2009-2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* local includes */ +#include + +using namespace Genode; + + +void Timer::Time_source::schedule_timeout(Microseconds duration, + Timeout_handler &handler) +{ + Genode::Lock::Guard lock_guard(_lock); + Threaded_time_source::handler(handler); + _next_timeout_us = duration.value; +} + + +void Timer::Time_source::_wait_for_irq() +{ + enum { SLEEP_GRANULARITY_US = 1000UL }; + unsigned long last_time_us = curr_time().value; + _lock.lock(); + while (_next_timeout_us > 0) { + _lock.unlock(); + + try { _usleep(SLEEP_GRANULARITY_US); } + catch (Blocking_canceled) { } + + unsigned long curr_time_us = curr_time().value; + unsigned long sleep_duration_us = curr_time_us - last_time_us; + last_time_us = curr_time_us; + + _lock.lock(); + if (_next_timeout_us >= sleep_duration_us) + _next_timeout_us -= sleep_duration_us; + else + break; + } + _lock.unlock(); +} diff --git a/repos/os/src/drivers/timer/spec/periodic/time_source.h b/repos/os/src/drivers/timer/spec/periodic/time_source.h new file mode 100644 index 000000000..7b6ad0961 --- /dev/null +++ b/repos/os/src/drivers/timer/spec/periodic/time_source.h @@ -0,0 +1,56 @@ +/* + * \brief Time source that uses sleeping by the means of the kernel + * \author Norman Feske + * \author Martin Stein + * \date 2009-06-16 + */ + +/* + * Copyright (C) 2009-2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _TIME_SOURCE_H_ +#define _TIME_SOURCE_H_ + +/* local includes */ +#include + +namespace Timer { class Time_source; } + + +class Timer::Time_source : public Threaded_time_source +{ + private: + + Genode::Lock mutable _lock; + unsigned long _curr_time_us = 0; + unsigned long _next_timeout_us = max_timeout().value; + + void _usleep(unsigned long us); + + + /************************** + ** Threaded_time_source ** + **************************/ + + void _wait_for_irq(); + + public: + + Time_source(Genode::Entrypoint &ep) : Threaded_time_source(ep) { + start(); } + + + /************************* + ** Genode::Time_source ** + *************************/ + + Microseconds curr_time() const override; + Microseconds max_timeout() const override; + void schedule_timeout(Microseconds duration, Timeout_handler &handler) override; +}; + +#endif /* _TIME_SOURCE_H_ */ diff --git a/repos/os/src/drivers/timer/spec/pistachio/platform_timer.cc b/repos/os/src/drivers/timer/spec/pistachio/time_source.cc similarity index 52% rename from repos/os/src/drivers/timer/spec/pistachio/platform_timer.cc rename to repos/os/src/drivers/timer/spec/pistachio/time_source.cc index 759e987dd..06f62a816 100644 --- a/repos/os/src/drivers/timer/spec/pistachio/platform_timer.cc +++ b/repos/os/src/drivers/timer/spec/pistachio/time_source.cc @@ -1,6 +1,7 @@ /* - * \brief Pistachio-specific sleep implementation + * \brief Time source that uses sleeping by the means of the kernel * \author Julian Stecklina + * \author Martin Stein * \date 2008-03-19 */ @@ -20,34 +21,37 @@ namespace Pistachio { } /* local includes */ -#include "timer_session_component.h" +#include + +using namespace Genode; +using Microseconds = Genode::Time_source::Microseconds; -unsigned long Platform_timer::max_timeout() +Microseconds Timer::Time_source::max_timeout() const { - Genode::Lock::Guard lock_guard(_lock); - return 1000*1000; + Lock::Guard lock_guard(_lock); + return Microseconds(1000 * 1000); } -unsigned long Platform_timer::curr_time() const +Microseconds Timer::Time_source::curr_time() const { - Genode::Lock::Guard lock_guard(_lock); - return _curr_time_usec; + Lock::Guard lock_guard(_lock); + return Microseconds(_curr_time_us); } -void Platform_timer::_usleep(unsigned long usecs) +void Timer::Time_source::_usleep(unsigned long us) { using namespace Pistachio; enum { MAGIC_USER_DEFINED_HANDLE = 13 }; L4_Set_UserDefinedHandle(MAGIC_USER_DEFINED_HANDLE); - L4_Sleep(L4_TimePeriod(usecs)); - _curr_time_usec += usecs; + L4_Sleep(L4_TimePeriod(us)); + _curr_time_us += us; /* check if sleep was canceled */ if (L4_UserDefinedHandle() != MAGIC_USER_DEFINED_HANDLE) - throw Genode::Blocking_canceled(); + throw Blocking_canceled(); } diff --git a/repos/os/src/drivers/timer/spec/pit/time_source.cc b/repos/os/src/drivers/timer/spec/pit/time_source.cc new file mode 100644 index 000000000..0047d8213 --- /dev/null +++ b/repos/os/src/drivers/timer/spec/pit/time_source.cc @@ -0,0 +1,118 @@ +/* + * \brief Time source that uses the Programmable Interval Timer (PIT) + * \author Norman Feske + * \author Martin Stein + * \date 2009-06-16 + */ + +/* + * Copyright (C) 2009-2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* local includes */ +#include + +using namespace Genode; +using Microseconds = Genode::Time_source::Microseconds; + + +void Timer::Time_source::_set_counter(uint16_t value) +{ + _handled_wrap = false; + _io_port.outb(PIT_DATA_PORT_0, value & 0xff); + _io_port.outb(PIT_DATA_PORT_0, (value >> 8) & 0xff); +} + + +uint16_t Timer::Time_source::_read_counter(bool *wrapped) +{ + /* read-back count and status of counter 0 */ + _io_port.outb(PIT_CMD_PORT, PIT_CMD_READ_BACK | + PIT_CMD_RB_COUNT | + PIT_CMD_RB_STATUS | + PIT_CMD_RB_CHANNEL_0); + + /* read status byte from latch register */ + uint8_t status = _io_port.inb(PIT_DATA_PORT_0); + + /* read low and high bytes from latch register */ + uint16_t lo = _io_port.inb(PIT_DATA_PORT_0); + uint16_t hi = _io_port.inb(PIT_DATA_PORT_0); + + *wrapped = status & PIT_STAT_INT_LINE ? true : false; + return (hi << 8) | lo; +} + + +void Timer::Time_source::schedule_timeout(Microseconds duration, + Timeout_handler &handler) +{ + _handler = &handler; + _timer_irq.ack_irq(); + unsigned long duration_us = duration.value; + + /* limit timer-interrupt rate */ + enum { MAX_TIMER_IRQS_PER_SECOND = 4*1000 }; + if (duration_us < 1000 * 1000 / MAX_TIMER_IRQS_PER_SECOND) + duration_us = 1000 * 1000 / MAX_TIMER_IRQS_PER_SECOND; + + if (duration_us > max_timeout().value) + duration_us = max_timeout().value; + + _counter_init_value = (PIT_TICKS_PER_MSEC * duration_us) / 1000; + _set_counter(_counter_init_value); +} + + +Microseconds Timer::Time_source::curr_time() const +{ + uint32_t passed_ticks; + + /* + * Read PIT count and status + * + * Reading the PIT registers via port I/O is a non-const operation. + * Since 'curr_time' is declared as const, however, we need to + * explicitly override the const-ness of the 'this' pointer. + */ + bool wrapped; + uint16_t const curr_counter = + const_cast(this)->_read_counter(&wrapped); + + /* determine the time since we looked at the counter */ + if (wrapped && !_handled_wrap) { + passed_ticks = _counter_init_value; + /* the counter really wrapped around */ + if (curr_counter) + passed_ticks += PIT_MAX_COUNT + 1 - curr_counter; + + _handled_wrap = true; + } else { + if (_counter_init_value) + passed_ticks = _counter_init_value - curr_counter; + else + passed_ticks = PIT_MAX_COUNT + 1 - curr_counter; + } + _curr_time_us += (passed_ticks*1000)/PIT_TICKS_PER_MSEC; + + /* use current counter as the reference for the next update */ + _counter_init_value = curr_counter; + return Microseconds(_curr_time_us); +} + + +Timer::Time_source::Time_source(Entrypoint &ep) +: + Signalled_time_source(ep), + _io_port(PIT_DATA_PORT_0, PIT_CMD_PORT - PIT_DATA_PORT_0 + 1), + _timer_irq(IRQ_PIT) +{ + /* operate PIT in one-shot mode */ + _io_port.outb(PIT_CMD_PORT, PIT_CMD_SELECT_CHANNEL_0 | + PIT_CMD_ACCESS_LO_HI | PIT_CMD_MODE_IRQ); + + _timer_irq.sigh(_signal_handler); +} diff --git a/repos/os/src/drivers/timer/spec/pit/time_source.h b/repos/os/src/drivers/timer/spec/pit/time_source.h new file mode 100644 index 000000000..350b99256 --- /dev/null +++ b/repos/os/src/drivers/timer/spec/pit/time_source.h @@ -0,0 +1,90 @@ +/* + * \brief Time source that uses the Programmable Interval Timer (PIT) + * \author Norman Feske + * \author Martin Stein + * \date 2009-06-16 + */ + +/* + * Copyright (C) 2009-2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _TIME_SOURCE_H_ +#define _TIME_SOURCE_H_ + +/* Genode includes */ +#include +#include + +/* local includes */ +#include + +namespace Timer { class Time_source; } + + +class Timer::Time_source : public Genode::Signalled_time_source +{ + private: + + + enum { + PIT_TICKS_PER_SECOND = 1193182, + PIT_TICKS_PER_MSEC = PIT_TICKS_PER_SECOND/1000, + PIT_MAX_COUNT = 65535, + PIT_DATA_PORT_0 = 0x40, /* data port for PIT channel 0, + connected to the PIC */ + PIT_CMD_PORT = 0x43, /* PIT command port */ + + PIT_MAX_USEC = (PIT_MAX_COUNT*1000)/(PIT_TICKS_PER_MSEC), + + IRQ_PIT = 0, /* timer interrupt at the PIC */ + + /* + * Bit definitions for accessing the PIT command port + */ + PIT_CMD_SELECT_CHANNEL_0 = 0 << 6, + PIT_CMD_ACCESS_LO = 1 << 4, + PIT_CMD_ACCESS_LO_HI = 3 << 4, + PIT_CMD_MODE_IRQ = 0 << 1, + PIT_CMD_MODE_RATE = 2 << 1, + + PIT_CMD_READ_BACK = 3 << 6, + PIT_CMD_RB_COUNT = 0 << 5, + PIT_CMD_RB_STATUS = 0 << 4, + PIT_CMD_RB_CHANNEL_0 = 1 << 1, + + /* + * Bit definitions of the PIT status byte + */ + PIT_STAT_INT_LINE = 1 << 7, + }; + + Genode::Io_port_connection _io_port; + Genode::Irq_connection _timer_irq; + unsigned long mutable _curr_time_us = 0; + Genode::uint16_t mutable _counter_init_value = 0; + bool mutable _handled_wrap = false; + + void _set_counter(Genode::uint16_t value); + + Genode::uint16_t _read_counter(bool *wrapped); + + public: + + Time_source(Genode::Entrypoint &ep); + + + /************************* + ** Genode::Time_source ** + *************************/ + + Microseconds curr_time() const override; + void schedule_timeout(Microseconds duration, Timeout_handler &handler) override; + Microseconds max_timeout() const override { + return Microseconds(PIT_MAX_USEC); } +}; + +#endif /* _TIME_SOURCE_H_ */