diff --git a/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp b/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp
index d0fd298..c19b735 100644
--- a/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp
+++ b/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp
@@ -377,7 +377,7 @@ namespace APIC
this->lapic->Write(APIC_TDCR, Divider);
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
- TimeManager->Sleep(1);
+ TimeManager->Sleep(1, Time::Units::Milliseconds);
// Mask the timer
this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */);
diff --git a/Core/Driver/DriverAPI.cpp b/Core/Driver/DriverAPI.cpp
index 5e41f61..e9e2640 100644
--- a/Core/Driver/DriverAPI.cpp
+++ b/Core/Driver/DriverAPI.cpp
@@ -144,7 +144,7 @@ void DriverSleep(unsigned long Milliseconds)
if (TaskManager)
TaskManager->Sleep(Milliseconds);
else
- TimeManager->Sleep(Milliseconds);
+ TimeManager->Sleep(Milliseconds, Time::Units::Milliseconds);
}
int Driversprintf(char *Buffer, const char *Format, ...)
diff --git a/Core/Lock.cpp b/Core/Lock.cpp
index f0f6bd8..f1b0cfb 100644
--- a/Core/Lock.cpp
+++ b/Core/Lock.cpp
@@ -187,7 +187,7 @@ Retry:
if (i >= (DebuggerIsAttached ? 0x100000 : 0x10000000))
{
if (Target.load() == 0)
- Target.store(TimeManager->CalculateTarget(Timeout));
+ Target.store(TimeManager->CalculateTarget(Timeout, Time::Units::Milliseconds));
TimeoutDeadLock(LockData, Target.load());
goto Retry;
}
diff --git a/Core/Time/HighPrecisionEventTimer.cpp b/Core/Time/HighPrecisionEventTimer.cpp
new file mode 100644
index 0000000..4a20986
--- /dev/null
+++ b/Core/Time/HighPrecisionEventTimer.cpp
@@ -0,0 +1,77 @@
+/*
+ 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 HighPrecisionEventTimer::Sleep(uint64_t Duration, Units Unit)
+ {
+#if defined(a86)
+ uint64_t Target = mminq(&((HPET *)hpet)->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk;
+ while (mminq(&((HPET *)hpet)->MainCounterValue) < Target)
+ CPU::Pause();
+ return true;
+#endif
+ }
+
+ uint64_t HighPrecisionEventTimer::GetCounter()
+ {
+#if defined(a86)
+ return mminq(&((HPET *)hpet)->MainCounterValue);
+#endif
+ }
+
+ uint64_t HighPrecisionEventTimer::CalculateTarget(uint64_t Target, Units Unit)
+ {
+#if defined(a86)
+ return mminq(&((HPET *)hpet)->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk;
+#endif
+ }
+
+ HighPrecisionEventTimer::HighPrecisionEventTimer(void *hpet)
+ {
+#if defined(a86)
+ ACPI::ACPI::HPETHeader *HPET_HDR = (ACPI::ACPI::HPETHeader *)hpet;
+ Memory::Virtual().Remap((void *)HPET_HDR->Address.Address,
+ (void *)HPET_HDR->Address.Address,
+ Memory::PTFlag::RW | Memory::PTFlag::PCD);
+ this->hpet = (HPET *)HPET_HDR->Address.Address;
+ trace("%s timer is at address %016p", HPET_HDR->Header.OEMID, (void *)HPET_HDR->Address.Address);
+ clk = s_cst(uint32_t, this->hpet->GeneralCapabilities >> 32);
+ mmoutq(&this->hpet->GeneralConfiguration, 0);
+ mmoutq(&this->hpet->MainCounterValue, 0);
+ mmoutq(&this->hpet->GeneralConfiguration, 1);
+#endif
+ }
+
+ HighPrecisionEventTimer::~HighPrecisionEventTimer()
+ {
+ }
+}
diff --git a/Core/Time.cpp b/Core/Time/Time.cpp
similarity index 100%
rename from Core/Time.cpp
rename to Core/Time/Time.cpp
diff --git a/Core/Time/Timer.cpp b/Core/Time/Timer.cpp
new file mode 100644
index 0000000..0883f50
--- /dev/null
+++ b/Core/Time/Timer.cpp
@@ -0,0 +1,148 @@
+/*
+ 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 time::Sleep(uint64_t Duration, Units Unit)
+ {
+ 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 hpet->Sleep(Duration, Unit);
+ case ACPI:
+ fixme("ACPI sleep not implemented");
+ return false;
+ case APIC:
+ fixme("APIC sleep not implemented");
+ return false;
+ case TSC:
+ fixme("TSC sleep not implemented");
+ return false;
+ default:
+ error("Unknown timer");
+ return false;
+ }
+ }
+
+ uint64_t time::GetCounter()
+ {
+ 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 hpet->GetCounter();
+ case ACPI:
+ fixme("ACPI sleep not implemented");
+ return false;
+ case APIC:
+ fixme("APIC sleep not implemented");
+ return false;
+ case TSC:
+ fixme("TSC sleep not implemented");
+ return false;
+ default:
+ error("Unknown timer");
+ return false;
+ }
+ }
+
+ uint64_t time::CalculateTarget(uint64_t Target, Units Unit)
+ {
+ 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 hpet->CalculateTarget(Target, Unit);
+ case ACPI:
+ fixme("ACPI sleep not implemented");
+ return false;
+ case APIC:
+ fixme("APIC sleep not implemented");
+ return false;
+ case TSC:
+ fixme("TSC sleep not implemented");
+ return false;
+ default:
+ error("Unknown timer");
+ return false;
+ }
+ }
+
+ time::time(void *acpi)
+ {
+ /* TODO: RTC check */
+ /* TODO: PIT check */
+
+ if (acpi)
+ {
+ if (((ACPI::ACPI *)acpi)->HPET)
+ {
+ hpet = new HighPrecisionEventTimer(((ACPI::ACPI *)acpi)->HPET);
+ ActiveTimer = HPET;
+ }
+
+ /* TODO: ACPI check */
+ /* TODO: APIC check */
+ }
+
+ /* TODO: TSC check */
+ }
+
+ time::~time()
+ {
+ debug("Destructor called");
+ }
+}
diff --git a/Core/Timer.cpp b/Core/Timer.cpp
deleted file mode 100644
index 0f40c1c..0000000
--- a/Core/Timer.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- 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
-{
- void time::Sleep(uint64_t Milliseconds)
- {
-#if defined(a86)
- uint64_t Target = mminq(&((HPET *)hpet)->MainCounterValue) + (Milliseconds * 1000000000000) / clk;
-#ifdef DEBUG
- uint64_t Counter = mminq(&((HPET *)hpet)->MainCounterValue);
- while (Counter < Target)
- {
- Counter = mminq(&((HPET *)hpet)->MainCounterValue);
- CPU::Pause();
- }
-#else
- while (mminq(&((HPET *)hpet)->MainCounterValue) < Target)
- CPU::Pause();
-#endif
-#elif defined(aa64)
-#endif
- }
-
- uint64_t time::GetCounter()
- {
-#if defined(a86)
- return mminq(&((HPET *)hpet)->MainCounterValue);
-#elif defined(aa64)
-#endif
- }
-
- uint64_t time::CalculateTarget(uint64_t Milliseconds)
- {
-#if defined(a86)
- return mminq(&((HPET *)hpet)->MainCounterValue) + (Milliseconds * 1000000000000) / clk;
-#elif defined(aa64)
-#endif
- }
-
- time::time(void *_acpi)
- {
- if (_acpi)
- {
-#if defined(a64)
- this->acpi = _acpi;
- ACPI::ACPI *acpi = (ACPI::ACPI *)this->acpi;
- if (acpi->HPET)
- {
- Memory::Virtual().Remap((void *)acpi->HPET->Address.Address,
- (void *)acpi->HPET->Address.Address,
- Memory::PTFlag::RW | Memory::PTFlag::PCD);
- this->hpet = (void *)acpi->HPET->Address.Address;
- HPET *hpet = (HPET *)this->hpet;
- trace("%s timer is at address %016p", acpi->HPET->Header.OEMID, (void *)acpi->HPET->Address.Address);
- clk = s_cst(uint32_t, hpet->GeneralCapabilities >> 32);
- mmoutq(&hpet->GeneralConfiguration, 0);
- mmoutq(&hpet->MainCounterValue, 0);
- mmoutq(&hpet->GeneralConfiguration, 1);
- }
- else
- {
- // For now, we need HPET.
- error("HPET not found");
- KPrint("\eFF2200HPET not found");
- CPU::Stop();
- }
-#elif defined(a32)
-#elif defined(aa64)
-#endif
- }
- }
-
- time::~time()
- {
- debug("Destructor called");
- }
-}
diff --git a/Execute/Elf/SharedObjects.cpp b/Execute/Elf/SharedObjects.cpp
index 8b7f2b7..3545f06 100644
--- a/Execute/Elf/SharedObjects.cpp
+++ b/Execute/Elf/SharedObjects.cpp
@@ -52,7 +52,7 @@ namespace Execute
{
if (Lib.RefCount > 0)
{
- Lib.Timeout = TimeManager->CalculateTarget(600000);
+ Lib.Timeout = TimeManager->CalculateTarget(10, Time::Units::Minutes);
debug("Reset timeout for %s", Lib.Identifier);
continue;
}
@@ -86,7 +86,7 @@ namespace Execute
}
strcpy(sl.Identifier, Identifier);
- sl.Timeout = TimeManager->CalculateTarget(600000); /* 10 minutes */
+ sl.Timeout = TimeManager->CalculateTarget(10, Time::Units::Minutes);
sl.RefCount = 0;
void *LibFile = mem->RequestPages(TO_PAGES(Length + 1), true);
diff --git a/Tasking/Task.cpp b/Tasking/Task.cpp
index 6b8abdd..783ba8a 100644
--- a/Tasking/Task.cpp
+++ b/Tasking/Task.cpp
@@ -288,7 +288,7 @@ namespace Tasking
thread->Status = TaskStatus::Sleeping;
if (thread->Parent->Threads.size() == 1)
thread->Parent->Status = TaskStatus::Sleeping;
- thread->Info.SleepUntil = TimeManager->CalculateTarget(Milliseconds);
+ thread->Info.SleepUntil = TimeManager->CalculateTarget(Milliseconds, Time::Units::Milliseconds);
tskdbg("Thread \"%s\"(%d) is going to sleep until %llu", thread->Name, thread->ID, thread->Info.SleepUntil);
// TaskingScheduler_OneShot(1);
// IRQ16
diff --git a/include/time.hpp b/include/time.hpp
index 72cdbaf..63fe1ac 100644
--- a/include/time.hpp
+++ b/include/time.hpp
@@ -19,6 +19,7 @@
#define __FENNIX_KERNEL_TIME_H__
#include
+#include
namespace Time
{
@@ -31,7 +32,22 @@ namespace Time
Clock ReadClock();
Clock ConvertFromUnix(int Timestamp);
- class time
+ enum Units
+ {
+ Femtoseconds,
+ Picoseconds,
+ Nanoseconds,
+ Microseconds,
+ Milliseconds,
+ Seconds,
+ Minutes,
+ Hours,
+ Days,
+ Months,
+ Years
+ };
+
+ class HighPrecisionEventTimer
{
private:
struct HPET
@@ -47,14 +63,70 @@ namespace Time
uint64_t Reserved4;
};
- void *acpi;
- void *hpet;
uint32_t clk = 0;
+ HPET *hpet;
+
+ 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:
- void Sleep(uint64_t Milliseconds);
+ bool Sleep(uint64_t Duration, Units Unit);
uint64_t GetCounter();
- uint64_t CalculateTarget(uint64_t Milliseconds);
+ uint64_t CalculateTarget(uint64_t Target, Units Unit);
+
+ HighPrecisionEventTimer(void *hpet);
+ ~HighPrecisionEventTimer();
+ };
+
+ class time
+ {
+ private:
+ enum _ActiveTimer
+ {
+ NONE,
+ RTC,
+ PIT,
+ HPET,
+ ACPI,
+ APIC,
+ TSC,
+ } ActiveTimer = NONE;
+
+ HighPrecisionEventTimer *hpet;
+
+ public:
+ bool Sleep(uint64_t Duration, Units Unit);
+ uint64_t GetCounter();
+ uint64_t CalculateTarget(uint64_t Target, Units Unit);
time(void *acpi);
~time();
};