From fa26805fd77c52f1fde2ea5fa0422a38f4bf0997 Mon Sep 17 00:00:00 2001 From: Reto Buerki Date: Thu, 23 Apr 2015 15:17:24 +0200 Subject: [PATCH] hw_x86_64_muen: Implement paravirt timer driver The driver uses the timer page containing a vector and timer value to implement the start_one_shot() and value() functions. The timer value designates the absolute tick count of the next event. The address of the time page is acquired using the get_memregion_info Sinfo API function. --- .../src/core/include/spec/x86_64_muen/timer.h | 73 +++++++++++++++++-- 1 file changed, 67 insertions(+), 6 deletions(-) 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 e28870ac1..97493884b 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) { } };