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__