diff --git a/repos/base-hw/src/core/include/spec/x86_64_muen/timer.h b/repos/base-hw/src/core/include/spec/x86_64_muen/timer.h
index e28870ac15..97493884b4 100644
--- a/repos/base-hw/src/core/include/spec/x86_64_muen/timer.h
+++ b/repos/base-hw/src/core/include/spec/x86_64_muen/timer.h
@@ -14,7 +14,11 @@
#ifndef _TIMER_H_
#define _TIMER_H_
-#include
+#include
+
+/* core includes */
+#include
+#include
namespace Genode
{
@@ -26,18 +30,75 @@ namespace Genode
class Genode::Timer
{
+ private:
+
+ enum {
+ TIMER_DISABLED = ~0ULL,
+ };
+
+ uint64_t _tics_per_ms;
+
+ struct Subject_timer
+ {
+ uint64_t value;
+ uint8_t vector;
+ } __attribute__((packed));
+
+ struct Subject_timer * _timer_page;
+
+ 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() { }
+ Timer() : _tics_per_ms(Sinfo::get_tsc_khz())
+ {
+ struct Sinfo::Memregion_info region;
+ if (!Sinfo::get_memregion_info("timer", ®ion)) {
+ PERR("muen-timer: Unable to retrieve time memory region");
+ throw Invalid_region();
+ }
- static unsigned interrupt_id(int) { return 0; }
+ _timer_page = (Subject_timer *)region.address;
+ _timer_page->vector = Board::TIMER_VECTOR_KERNEL;
+ PINF("muen-timer: page @0x%llx, frequency %llu kHz, vector %u",
+ region.address, _tics_per_ms, _timer_page->vector);
+ }
- inline void start_one_shot(uint32_t const tics, unsigned) { }
+ static unsigned interrupt_id(int)
+ {
+ return Board::TIMER_VECTOR_KERNEL;
+ }
- uint32_t ms_to_tics(unsigned const ms) { return 1000; }
+ inline void start_one_shot(uint32_t const tics, unsigned)
+ {
+ _timer_page->value = rdtsc() + tics;
+ }
- unsigned value(unsigned) { return 0; }
+ uint32_t ms_to_tics(unsigned const ms)
+ {
+ return ms * _tics_per_ms;
+ }
+ unsigned value(unsigned)
+ {
+ const uint64_t now = rdtsc();
+ if (_timer_page->value != TIMER_DISABLED
+ && _timer_page->value > now) {
+ return _timer_page->value - now;
+ }
+ return 0;
+ }
+
+ /*
+ * Dummies
+ */
static void disable_pit(void) { }
};