Files
jsix/src/kernel/hpet.cpp
Justin C. Miller f5208d1641 [all] Remove dependencies on non-freestanding libc
This is the first of two rather big changes to clean up includes
throughout the project. In this commit, the implicit semi-dependency on
libc that bonnibel adds to every module is removed. Previously, I was
sloppy with includes of libc headers and include directory order. Now,
the freestanding headers from libc are split out into libc_free, and an
implicit real dependency is added onto this module, unless `no_libc` is
set to `True`. The full libc needs to be explicitly specified as a
dependency to be used.

Several things needed to change in order to do this:

- Many places use `memset` or `memcpy` that cannot depend on libc. The
  kernel has basic implementations of them itself for this reason. Now
  those functions are moved into the lower-level `j6/memutils.h`, and
  libc merely references them. Other modules are now free to reference
  those functions from libj6 instead.
- The kernel's `assert.h` was renamed kassert.h (matching its `kassert`
  function) so that the new `util/assert.h` can use `__has_include` to
  detect it and make sure the `assert` macro is usable in libutil code.
- Several implementation header files under `__libj6/` also moved under
  the new libc_free.
- A new `include_phase` property has been added to modules for Bonnibel,
  which can be "normal" (default) or "late" which uses `-idirafter`
  instead of `-I` for includes.
- Since `<utility>` and `<new>` are not freestanding, implementations of
  `remove_reference`, `forward`, `move`, and `swap` were added to the
  `util` namespace to replace those from `std`, and `util/new.h` was
  added to declare `operator new` and `operator delete`.
2023-07-12 19:38:31 -07:00

119 lines
3.9 KiB
C++

#include "kassert.h"
#include "device_manager.h"
#include "hpet.h"
#include "io.h"
#include "logger.h"
namespace {
inline uint64_t volatile *capabilities(uint64_t volatile *base) { return base; }
inline uint64_t volatile *configuration(uint64_t volatile *base) { return base+2; }
inline uint64_t volatile *interrupt_status(uint64_t volatile *base) { return base+4; }
inline uint64_t volatile *counter_value(uint64_t volatile *base) { return base+30; }
inline uint64_t volatile *timer_base(uint64_t volatile *base, unsigned i) { return base + 0x20 + (4*i); }
inline uint64_t volatile *timer_config(uint64_t volatile *base, unsigned i) { return timer_base(base, i); }
inline uint64_t volatile *timer_comparator(uint64_t volatile *base, unsigned i) { return timer_base(base, i) + 1; }
}
void
hpet_irq_callback(void *hpet_ptr)
{
if (hpet_ptr)
reinterpret_cast<hpet*>(hpet_ptr)->callback();
}
hpet::hpet(uint8_t index, uint64_t *base) :
m_index(index),
m_base(base)
{
*configuration(m_base) = 0;
*counter_value(m_base) = 0;
uint64_t caps = *capabilities(base);
uint64_t config = *configuration(base);
m_timers = ((caps >> 8) & 0x1f) + 1;
m_period = (caps >> 32);
setup_timer_interrupts(0, 2, 1000, true);
// bool installed = device_manager::get()
// .install_irq(2, "HPET Timer", hpet_irq_callback, this);
// kassert(installed, "Installing HPET IRQ handler");
log::spam(logs::timer, "HPET %d capabilities:", index);
log::spam(logs::timer, " revision: %d", caps & 0xff);
log::spam(logs::timer, " timers: %d", m_timers);
log::spam(logs::timer, " bits: %d", ((caps >> 13) & 1) ? 64 : 32);
log::spam(logs::timer, " LRR capable: %d", ((caps >> 15) & 1));
log::spam(logs::timer, " period: %dns", m_period / 1000000);
log::spam(logs::timer, " global enabled: %d", config & 1);
log::spam(logs::timer, " LRR enable: %d", (config >> 1) & 1);
for (unsigned i = 0; i < m_timers; ++i) {
disable_timer(i);
uint64_t config = *timer_config(m_base, i);
log::spam(logs::timer, "HPET %d timer %d:", index, i);
log::spam(logs::timer, " int type: %d", (config >> 1) & 1);
log::spam(logs::timer, " int enable: %d", (config >> 2) & 1);
log::spam(logs::timer, " timer type: %d", (config >> 3) & 1);
log::spam(logs::timer, " periodic cap: %d", (config >> 4) & 1);
log::spam(logs::timer, " bits: %d", ((config >> 5) & 1) ? 64 : 32);
log::spam(logs::timer, " 32 mode: %d", (config >> 8) & 1);
log::spam(logs::timer, " int route: %d", (config >> 9) & 0x1f);
log::spam(logs::timer, " FSB enable: %d", (config >> 14) & 1);
log::spam(logs::timer, " FSB capable: %d", (config >> 15) & 1);
log::spam(logs::timer, " rotung cap: %08x", (config >> 32));
}
}
void
hpet::setup_timer_interrupts(unsigned timer, uint8_t irq, uint64_t interval, bool periodic)
{
constexpr uint64_t femto_per_us = 1000000000ull;
*timer_comparator(m_base, timer) =
*counter_value(m_base) +
(interval * femto_per_us) / m_period;
*timer_config(m_base, timer) = (irq << 9) | ((periodic ? 1 : 0) << 3);
}
void
hpet::enable_timer(unsigned timer)
{
*timer_config(m_base, timer) = *timer_config(m_base, timer) | (1 << 2);
}
void
hpet::disable_timer(unsigned timer)
{
*timer_config(m_base, timer) = *timer_config(m_base, timer) & ~(1ull << 2);
}
void
hpet::callback()
{
log::spam(logs::timer, "HPET %d got irq", m_index);
}
void
hpet::enable()
{
log::verbose(logs::timer, "HPET %d enabling", m_index);
*configuration(m_base) = (*configuration(m_base) & 0x3) | 1;
}
uint64_t
hpet::value() const
{
return *counter_value(m_base);
}
uint64_t
hpet_clock_source(void *data)
{
return reinterpret_cast<hpet*>(data)->value();
}