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(); };