diff --git a/Core/Time/HighPrecisionEventTimer.cpp b/Core/Time/HighPrecisionEventTimer.cpp index 4a20986..440d7e3 100644 --- a/Core/Time/HighPrecisionEventTimer.cpp +++ b/Core/Time/HighPrecisionEventTimer.cpp @@ -55,6 +55,13 @@ namespace Time #endif } + uint64_t HighPrecisionEventTimer::GetMillisecondsSinceClassCreation() + { +#if defined(a86) + return (this->GetCounter() - this->ClassCreationTime) / (this->clk / this->ConvertUnit(Units::Milliseconds)); +#endif + } + HighPrecisionEventTimer::HighPrecisionEventTimer(void *hpet) { #if defined(a86) @@ -68,6 +75,7 @@ namespace Time mmoutq(&this->hpet->GeneralConfiguration, 0); mmoutq(&this->hpet->MainCounterValue, 0); mmoutq(&this->hpet->GeneralConfiguration, 1); + ClassCreationTime = this->GetCounter(); #endif } diff --git a/Core/Time/TimeStampCounter.cpp b/Core/Time/TimeStampCounter.cpp new file mode 100644 index 0000000..6b7e5b0 --- /dev/null +++ b/Core/Time/TimeStampCounter.cpp @@ -0,0 +1,81 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#include + +#include +#include +#include + +#if defined(a64) +#include "../../Architecture/amd64/acpi.hpp" +#elif defined(a32) +#elif defined(aa64) +#endif + +#include "../../kernel.h" + +namespace Time +{ + bool TimeStampCounter::Sleep(uint64_t Duration, Units Unit) + { +#if defined(a86) + uint64_t Target = this->GetCounter() + (Duration * ConvertUnit(Unit)) / this->clk; + while (this->GetCounter() < Target) + CPU::Pause(); + return true; +#endif + } + + uint64_t TimeStampCounter::GetCounter() + { +#if defined(a86) + return CPU::Counter(); +#endif + } + + uint64_t TimeStampCounter::CalculateTarget(uint64_t Target, Units Unit) + { +#if defined(a86) + return this->GetCounter() + (Target * ConvertUnit(Unit)) / this->clk; +#endif + } + + uint64_t TimeStampCounter::GetMillisecondsSinceClassCreation() + { +#if defined(a86) + return (this->GetCounter() - this->ClassCreationTime) / this->clk; +#endif + } + + TimeStampCounter::TimeStampCounter() + { +#if defined(a86) + fixme(""); // FIXME: This is not a good way to measure the clock speed + uint64_t Start = CPU::Counter(); + TimeManager->Sleep(1, Units::Milliseconds); + uint64_t End = CPU::Counter(); + + this->clk = End - Start; + this->ClassCreationTime = this->GetCounter(); +#endif + } + + TimeStampCounter::~TimeStampCounter() + { + } +} diff --git a/Core/Time/Timer.cpp b/Core/Time/Timer.cpp index 0883f50..6fd9801 100644 --- a/Core/Time/Timer.cpp +++ b/Core/Time/Timer.cpp @@ -45,7 +45,7 @@ namespace Time fixme("PIT sleep not implemented"); return false; case HPET: - return hpet->Sleep(Duration, Unit); + return this->hpet->Sleep(Duration, Unit); case ACPI: fixme("ACPI sleep not implemented"); return false; @@ -53,8 +53,7 @@ namespace Time fixme("APIC sleep not implemented"); return false; case TSC: - fixme("TSC sleep not implemented"); - return false; + return this->tsc->Sleep(Duration, Unit); default: error("Unknown timer"); return false; @@ -75,7 +74,7 @@ namespace Time fixme("PIT sleep not implemented"); return false; case HPET: - return hpet->GetCounter(); + return this->hpet->GetCounter(); case ACPI: fixme("ACPI sleep not implemented"); return false; @@ -83,8 +82,7 @@ namespace Time fixme("APIC sleep not implemented"); return false; case TSC: - fixme("TSC sleep not implemented"); - return false; + return this->tsc->GetCounter(); default: error("Unknown timer"); return false; @@ -105,7 +103,7 @@ namespace Time fixme("PIT sleep not implemented"); return false; case HPET: - return hpet->CalculateTarget(Target, Unit); + return this->hpet->CalculateTarget(Target, Unit); case ACPI: fixme("ACPI sleep not implemented"); return false; @@ -113,15 +111,43 @@ namespace Time fixme("APIC sleep not implemented"); return false; case TSC: - fixme("TSC sleep not implemented"); - return false; + return this->tsc->CalculateTarget(Target, Unit); default: error("Unknown timer"); return false; } } - time::time(void *acpi) + uint64_t time::GetMillisecondsSinceClassCreation() + { + switch (ActiveTimer) + { + case NONE: + error("No timer is active"); + return false; + case RTC: + fixme("RTC sleep not implemented"); + return false; + case PIT: + fixme("PIT sleep not implemented"); + return false; + case HPET: + return this->hpet->GetMillisecondsSinceClassCreation(); + case ACPI: + fixme("ACPI sleep not implemented"); + return false; + case APIC: + fixme("APIC sleep not implemented"); + return false; + case TSC: + return this->tsc->GetMillisecondsSinceClassCreation(); + default: + error("Unknown timer"); + return false; + } + } + + void time::FindTimers(void *acpi) { /* TODO: RTC check */ /* TODO: PIT check */ @@ -132,17 +158,56 @@ namespace Time { hpet = new HighPrecisionEventTimer(((ACPI::ACPI *)acpi)->HPET); ActiveTimer = HPET; + SupportedTimers |= HPET; + KPrint("\e11FF11HPET found"); + } + else + { + KPrint("\eFF2200HPET not found"); } /* TODO: ACPI check */ /* TODO: APIC check */ } + else + { + KPrint("\eFF2200ACPI not found"); + } - /* TODO: TSC check */ + bool TSCInvariant = false; + if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) + { + CPU::x86::AMD::CPUID0x80000007 cpuid80000007; + cpuid80000007.Get(); + if (cpuid80000007.EDX.TscInvariant) + TSCInvariant = true; + } + else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0) + { + // TODO: Intel 0x80000007 + CPU::x86::AMD::CPUID0x80000007 cpuid80000007; + cpuid80000007.Get(); + if (cpuid80000007.EDX.TscInvariant) + TSCInvariant = true; + } + + if (TSCInvariant) + { + tsc = new TimeStampCounter; + // FIXME: ActiveTimer = TSC; + SupportedTimers |= TSC; + KPrint("\e11FF11Invariant TSC found"); + } + else + KPrint("\eFF2200TSC is not invariant"); + + } + + time::time() + { } time::~time() { - debug("Destructor called"); } } diff --git a/Kernel.cpp b/Kernel.cpp index 4666734..db2a7b7 100644 --- a/Kernel.cpp +++ b/Kernel.cpp @@ -316,13 +316,8 @@ EXTERNC NIF void Main(BootInfo *Info) #endif KPrint("Initializing Timers"); -#if defined(a64) - TimeManager = new Time::time(PowerManager->GetACPI()); -#elif defined(a32) - TimeManager = new Time::time(PowerManager->GetACPI()); -#elif defined(aa64) - TimeManager = new Time::time(nullptr); -#endif + TimeManager = new Time::time; + TimeManager->FindTimers(PowerManager->GetACPI()); KPrint("Initializing Bootstrap Processor Timer"); Interrupts::InitializeTimer(0); diff --git a/include/time.hpp b/include/time.hpp index 63fe1ac..f342c6c 100644 --- a/include/time.hpp +++ b/include/time.hpp @@ -64,9 +64,10 @@ namespace Time }; uint32_t clk = 0; - HPET *hpet; + HPET *hpet = nullptr; + uint64_t ClassCreationTime = 0; - uint64_t ConvertUnit(Units Unit) + inline uint64_t ConvertUnit(Units Unit) { switch (Unit) { @@ -102,34 +103,100 @@ namespace Time bool Sleep(uint64_t Duration, Units Unit); uint64_t GetCounter(); uint64_t CalculateTarget(uint64_t Target, Units Unit); + uint64_t GetMillisecondsSinceClassCreation(); HighPrecisionEventTimer(void *hpet); ~HighPrecisionEventTimer(); }; - class time + class TimeStampCounter { private: - enum _ActiveTimer - { - NONE, - RTC, - PIT, - HPET, - ACPI, - APIC, - TSC, - } ActiveTimer = NONE; + uint64_t clk = 0; + uint64_t ClassCreationTime = 0; - HighPrecisionEventTimer *hpet; + inline uint64_t ConvertUnit(Units Unit) + { + switch (Unit) + { + case Femtoseconds: + return 1; + case Picoseconds: + return 1000; + case Nanoseconds: + return 1000000; + case Microseconds: + return 1000000000; + case Milliseconds: + return 1000000000000; + case Seconds: + return 1000000000000000; + case Minutes: + return 1000000000000000000; + // case Hours: + // return 1000000000000000000000; + // case Days: + // return 1000000000000000000000000; + // case Months: + // return 1000000000000000000000000000; + // case Years: + // return 1000000000000000000000000000000; + default: + error("Invalid time unit %d", Unit); + return 1; + } + } public: bool Sleep(uint64_t Duration, Units Unit); uint64_t GetCounter(); uint64_t CalculateTarget(uint64_t Target, Units Unit); - time(void *acpi); + uint64_t GetMillisecondsSinceClassCreation(); + + TimeStampCounter(); + ~TimeStampCounter(); + }; + + class time + { + public: + enum TimeActiveTimer + { + NONE = 0b0, + RTC = 0b1, + PIT = 0b10, + HPET = 0b100, + ACPI = 0b1000, + APIC = 0b10000, + TSC = 0b100000 + }; + + private: + int SupportedTimers = 0; + TimeActiveTimer ActiveTimer = NONE; + + HighPrecisionEventTimer *hpet; + TimeStampCounter *tsc; + + public: + int GetSupportedTimers() { return SupportedTimers; } + TimeActiveTimer GetActiveTimer() { return ActiveTimer; } + bool ChangeActiveTimer(TimeActiveTimer Timer) + { + if (!(SupportedTimers & Timer)) + return false; + ActiveTimer = Timer; + return true; + } + + bool Sleep(uint64_t Duration, Units Unit); + uint64_t GetCounter(); + uint64_t CalculateTarget(uint64_t Target, Units Unit); + uint64_t GetMillisecondsSinceClassCreation(); + void FindTimers(void *acpi); + time(); ~time(); }; } - + #endif // !__FENNIX_KERNEL_TIME_H__