feat: enhance timer
This commit is contained in:
parent
43c87e5904
commit
54d48e7d91
5 changed files with 133 additions and 8 deletions
|
|
@ -1,15 +1,57 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "acpi/madt.h"
|
#include "acpi/madt.h"
|
||||||
#include "util/optional.h"
|
|
||||||
|
|
||||||
namespace apic {
|
namespace apic {
|
||||||
|
|
||||||
struct lapic_timer_calibration_t {
|
struct duration_t {
|
||||||
uint64_t tsc_frequency_hz;
|
uint64_t timer_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
optional<lapic_timer_calibration_t> calibrateTimer(const acpi::Madt& madt);
|
struct timestamp_t {
|
||||||
|
uint64_t timer_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr duration_t operator+(duration_t left, duration_t right) {
|
||||||
|
return duration_t{left.timer_count + right.timer_count};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr duration_t operator-(duration_t left, duration_t right) {
|
||||||
|
return duration_t{left.timer_count - right.timer_count};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr duration_t operator*(duration_t duration, uint64_t scalar) {
|
||||||
|
return duration_t{duration.timer_count * scalar};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr duration_t operator*(uint64_t scalar, duration_t duration) {
|
||||||
|
return duration_t{duration.timer_count * scalar};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr timestamp_t operator+(timestamp_t timestamp, duration_t duration) {
|
||||||
|
return timestamp_t{timestamp.timer_count + duration.timer_count};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr timestamp_t operator+(duration_t duration, timestamp_t timestamp) {
|
||||||
|
return timestamp_t{timestamp.timer_count + duration.timer_count};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr timestamp_t operator-(timestamp_t timestamp, duration_t duration) {
|
||||||
|
return timestamp_t{timestamp.timer_count - duration.timer_count};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr duration_t operator-(timestamp_t left, timestamp_t right) {
|
||||||
|
return duration_t{left.timer_count - right.timer_count};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool calibrateTimer(const acpi::Madt& madt);
|
||||||
|
|
||||||
|
duration_t seconds(uint64_t count);
|
||||||
|
duration_t milliseconds(uint64_t count);
|
||||||
|
duration_t microseconds(uint64_t count);
|
||||||
|
duration_t nanoseconds(uint64_t count);
|
||||||
|
|
||||||
|
timestamp_t now();
|
||||||
|
|
||||||
// TODO: when dynamic allocation and lists are available
|
// TODO: when dynamic allocation and lists are available
|
||||||
// struct Timer {};
|
// struct Timer {};
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,10 @@ auto construct() {
|
||||||
return Type{forward<decltype(args)>(args)...};
|
return Type{forward<decltype(args)>(args)...};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename V>
|
||||||
|
auto constant(V v) {
|
||||||
|
return [v](auto _) {
|
||||||
|
return v;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -183,3 +183,24 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct as_optional {
|
||||||
|
using type = optional<T>;
|
||||||
|
};
|
||||||
|
template<typename T>
|
||||||
|
struct as_optional<optional<T>> {
|
||||||
|
using type = optional<T>;
|
||||||
|
};
|
||||||
|
template<typename T>
|
||||||
|
using as_optional_t = typename as_optional<T>::type;
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
auto lift(Func func) {
|
||||||
|
return [func](const auto&... optionals) -> as_optional_t<decltype(func(optionals.value()...))> {
|
||||||
|
if ((optionals.has_value() && ...)) {
|
||||||
|
return func(optionals.value()...);
|
||||||
|
}
|
||||||
|
return nullopt;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
#include "apic/timer.h"
|
#include "apic/timer.h"
|
||||||
|
|
||||||
#include "util/cpuid.h"
|
#include "util/cpuid.h"
|
||||||
#include "util/function.h"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
|
@ -11,6 +10,12 @@ constexpr uint32_t processor_frequency_leaf = 0x16;
|
||||||
|
|
||||||
constexpr uint32_t feature_edx_tsc = 1u << 4;
|
constexpr uint32_t feature_edx_tsc = 1u << 4;
|
||||||
|
|
||||||
|
struct lapic_timer_calibration_t {
|
||||||
|
uint64_t tsc_frequency_hz;
|
||||||
|
};
|
||||||
|
|
||||||
|
lapic_timer_calibration_t timer_calibration{};
|
||||||
|
|
||||||
bool isTscSupported() {
|
bool isTscSupported() {
|
||||||
return cpuid(feature_info_leaf)
|
return cpuid(feature_info_leaf)
|
||||||
.map([](const cpuid_result_t& features) {
|
.map([](const cpuid_result_t& features) {
|
||||||
|
|
@ -45,11 +50,46 @@ optional<uint64_t> tscFrequency() {
|
||||||
return tscFrequencyFromCrystalRatio().or_else(tscFrequencyFromProcessorBase);
|
return tscFrequencyFromCrystalRatio().or_else(tscFrequencyFromProcessorBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apic::duration_t durationFromUnit(uint64_t count, uint64_t units_per_second) {
|
||||||
|
uint64_t whole_seconds = count / units_per_second;
|
||||||
|
uint64_t remainder_units = count % units_per_second;
|
||||||
|
return apic::duration_t{whole_seconds * timer_calibration.tsc_frequency_hz +
|
||||||
|
remainder_units * timer_calibration.tsc_frequency_hz / units_per_second};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
optional<apic::lapic_timer_calibration_t> apic::calibrateTimer(const acpi::Madt&) {
|
bool apic::calibrateTimer(const acpi::Madt&) {
|
||||||
if (!isTscSupported()) {
|
if (!isTscSupported()) {
|
||||||
return {};
|
return false;
|
||||||
}
|
}
|
||||||
return tscFrequency().map(construct<lapic_timer_calibration_t>());
|
return tscFrequency()
|
||||||
|
.map([](uint64_t tsc_frequency_hz) {
|
||||||
|
timer_calibration.tsc_frequency_hz = tsc_frequency_hz;
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.value_or(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
apic::duration_t apic::seconds(uint64_t count) {
|
||||||
|
return duration_t{count * timer_calibration.tsc_frequency_hz};
|
||||||
|
}
|
||||||
|
|
||||||
|
apic::duration_t apic::milliseconds(uint64_t count) {
|
||||||
|
return durationFromUnit(count, 1'000);
|
||||||
|
}
|
||||||
|
|
||||||
|
apic::duration_t apic::microseconds(uint64_t count) {
|
||||||
|
return durationFromUnit(count, 1'000'000);
|
||||||
|
}
|
||||||
|
|
||||||
|
apic::duration_t apic::nanoseconds(uint64_t count) {
|
||||||
|
return durationFromUnit(count, 1'000'000'000);
|
||||||
|
}
|
||||||
|
|
||||||
|
apic::timestamp_t apic::now() {
|
||||||
|
uint32_t low = 0;
|
||||||
|
uint32_t high = 0;
|
||||||
|
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
|
||||||
|
return timestamp_t{(static_cast<uint64_t>(high) << 32) | low};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "init/init.h"
|
#include "init/init.h"
|
||||||
#include "acpi/acpi.h"
|
#include "acpi/acpi.h"
|
||||||
#include "acpi/madt.h"
|
#include "acpi/madt.h"
|
||||||
|
#include "apic/timer.h"
|
||||||
#include "init/multiboot2.h"
|
#include "init/multiboot2.h"
|
||||||
#include "init/print.h"
|
#include "init/print.h"
|
||||||
#include "memory/allocator.h"
|
#include "memory/allocator.h"
|
||||||
|
|
@ -200,10 +201,24 @@ static AcpiDiscoveryResult setupAcpi() {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void calibrateTimer(optional<acpi::Madt> madt) {
|
||||||
|
auto success = madt.map(apic::calibrateTimer).value_or(false);
|
||||||
|
if (!success) {
|
||||||
|
panic("Could not calibrate timer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[[maybe_unused]] [[noreturn]] __attribute__((used)) void init() {
|
[[maybe_unused]] [[noreturn]] __attribute__((used)) void init() {
|
||||||
initFromLow();
|
initFromLow();
|
||||||
print("Reached init\n");
|
print("Reached init\n");
|
||||||
step("memory", setupMemory);
|
step("memory", setupMemory);
|
||||||
auto acpi = step("acpi", setupAcpi);
|
auto acpi = step("acpi", setupAcpi);
|
||||||
|
step("timer", partial(calibrateTimer, acpi.madt));
|
||||||
|
auto now = apic::now();
|
||||||
|
print_hex(now.timer_count);
|
||||||
|
now = apic::now();
|
||||||
|
print_hex(now.timer_count);
|
||||||
|
now = apic::now();
|
||||||
|
print_hex(now.timer_count);
|
||||||
halt();
|
halt();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue