This patch adds very limited support of hpets with 32-bit main counter. For now it does not handle wrap-around (typically around 7 minutes) but is enough to run 'hello world' example on platforms that support hpet with 32-bit main counter only like hyperkit.
It also refactors the hpet code to allow for future refinements of both 32-bit and 64-bit implementations independently. Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com> --- drivers/hpet.cc | 70 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/drivers/hpet.cc b/drivers/hpet.cc index a051eb95..22afae7d 100644 --- a/drivers/hpet.cc +++ b/drivers/hpet.cc @@ -23,36 +23,60 @@ using boost::intrusive::get_parent_from_member; class hpetclock : public clock { public: - hpetclock(uint64_t hpet_address); - virtual s64 time() __attribute__((no_instrument_function)); - virtual s64 uptime() override __attribute__((no_instrument_function)); + hpetclock(mmioaddr_t hpet_mmio_address); virtual s64 boot_time() override __attribute__((no_instrument_function)); -private: +protected: mmioaddr_t _addr; uint64_t _wall; uint64_t _period; }; +#define HPET_COUNTER 0x0f0 + +//FIXME: Enhance this class to handle wrap-around +class hpet_32bit_clock : public hpetclock { +public: + hpet_32bit_clock(mmioaddr_t hpet_mmio_address) : hpetclock(hpet_mmio_address) { + debug_early_u64("WARNING: hpet with 32-bit counter will wrap around in seconds: ", + (_period * (1UL << 32)) / 1000000000UL); + } +protected: + virtual s64 time() override __attribute__((no_instrument_function)) { + return _wall + mmio_getl(_addr + HPET_COUNTER) * _period; + } + + virtual s64 uptime() override __attribute__((no_instrument_function)) { + return mmio_getl(_addr + HPET_COUNTER) * _period; + } +}; + +class hpet_64bit_clock : public hpetclock { +public: + hpet_64bit_clock(mmioaddr_t hpet_mmio_address) : hpetclock(hpet_mmio_address) {} +protected: + virtual s64 time() override __attribute__((no_instrument_function)) { + return _wall + mmio_getq(_addr + HPET_COUNTER) * _period;; + } + + virtual s64 uptime() override __attribute__((no_instrument_function)) { + return mmio_getq(_addr + HPET_COUNTER) * _period;; + } +}; + #define HPET_CAP 0x000 #define HPET_CAP_COUNT_SIZE (1<<13) #define HPET_PERIOD 0x004 #define HPET_CONFIG 0x010 -#define HPET_COUNTER 0x0f0 #define MAX_PERIOD 100000000UL #define MIN_PERIOD 1000000UL -hpetclock::hpetclock(uint64_t hpet_address) +hpetclock::hpetclock(mmioaddr_t hpet_mmio_address) { + _addr = hpet_mmio_address; // If we ever need another rtc user, it should be global. But // we should really, really avoid it. So let it local. auto r = new rtc(); - _addr = mmio_map(hpet_address, 4096); - - // Verify that a 64-bit counter is supported, and we're not forced to - // operate in 32-bit mode (which has interrupt on every wrap-around). - auto cap = mmio_getl(_addr + HPET_CAP); - assert(cap & HPET_CAP_COUNT_SIZE); unsigned int cfg = mmio_getl(_addr + HPET_CONFIG); // Stop the HPET First, so we can make sure the counter is at 0 when we @@ -83,16 +107,6 @@ hpetclock::hpetclock(uint64_t hpet_address) }; } -s64 hpetclock::time() -{ - return _wall + (mmio_getq(_addr + HPET_COUNTER) * _period); -} - -s64 hpetclock::uptime() -{ - return mmio_getq(_addr + HPET_COUNTER) * _period; -} - s64 hpetclock::boot_time() { // The following is time()-uptime(): @@ -122,6 +136,16 @@ void __attribute__((constructor(init_prio::hpet))) hpet_init() auto h = get_parent_from_member(hpet_header, &ACPI_TABLE_HPET::Header); auto hpet_address = h->Address; - clock::register_clock(new hpetclock(hpet_address.Address)); + // Check what type of main counter - 32-bit or 64-bit - is available and + // construct relevant hpet clock instance + mmioaddr_t hpet_mmio_address = mmio_map(hpet_address.Address, 4096); + + auto cap = mmio_getl(hpet_mmio_address + HPET_CAP); + if (cap & HPET_CAP_COUNT_SIZE) { + clock::register_clock(new hpet_64bit_clock(hpet_mmio_address)); + } + else { + clock::register_clock(new hpet_32bit_clock(hpet_mmio_address)); + } }, {}); } -- 2.20.1 -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/20190628031453.4445-1-jwkozaczuk%40gmail.com. For more options, visit https://groups.google.com/d/optout.