diff --git a/Kernel/arch/amd64/cpu/apic.cpp b/Kernel/arch/amd64/cpu/apic.cpp index c0588bc9..0b4169d6 100644 --- a/Kernel/arch/amd64/cpu/apic.cpp +++ b/Kernel/arch/amd64/cpu/apic.cpp @@ -442,7 +442,7 @@ namespace APIC this->lapic->Write(APIC_TICR, 0xFFFFFFFF); } - TimeManager->Sleep(1, Time::Units::Milliseconds); + TimeManager->Sleep(Time::FromMilliseconds(1)); // Mask the timer if (this->lapic->x2APIC) diff --git a/Kernel/arch/amd64/cpu/smp.cpp b/Kernel/arch/amd64/cpu/smp.cpp index 428d66c2..6432f520 100644 --- a/Kernel/arch/amd64/cpu/smp.cpp +++ b/Kernel/arch/amd64/cpu/smp.cpp @@ -167,14 +167,14 @@ namespace SMP } apic->SendInitIPI(lapic->APICId); - TimeManager->Sleep(20, Time::Units::Milliseconds); + TimeManager->Sleep(Time::FromMilliseconds(20)); apic->SendStartupIPI(lapic->APICId, TRAMPOLINE_START); debug("Waiting for CPU %d to load...", lapic->APICId); - uint64_t Timeout = TimeManager->CalculateTarget(2, Time::Units::Seconds); + uint64_t Timeout = TimeManager->GetTimeNs() + Time::FromSeconds(2); while (CPUEnabled.load(std::memory_order_acquire) == false) { - if (TimeManager->GetCounter() > Timeout) + if (TimeManager->GetTimeNs() > Timeout) { error("CPU %d failed to load!", lapic->APICId); KPrint("\x1b[1;37;41mCPU %d failed to load!", diff --git a/Kernel/arch/i386/cpu/apic.cpp b/Kernel/arch/i386/cpu/apic.cpp index a0dd750b..e450082b 100644 --- a/Kernel/arch/i386/cpu/apic.cpp +++ b/Kernel/arch/i386/cpu/apic.cpp @@ -368,7 +368,7 @@ namespace APIC this->lapic->Write(APIC_TDCR, DivideBy128); else this->lapic->Write(APIC_TDCR, DivideBy16); - this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks * Miliseconds)); + this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks *Miliseconds)); this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw)); } @@ -383,7 +383,7 @@ namespace APIC this->lapic->Write(APIC_TDCR, Divider); this->lapic->Write(APIC_TICR, 0xFFFFFFFF); - TimeManager->Sleep(1, Time::Units::Milliseconds); + TimeManager->Sleep(Time::FromMilliseconds(1)); // Mask the timer this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */); diff --git a/Kernel/core/console.cpp b/Kernel/core/console.cpp index f36bba05..f3181d02 100644 --- a/Kernel/core/console.cpp +++ b/Kernel/core/console.cpp @@ -25,6 +25,8 @@ #include "../kernel.h" +using namespace std::chrono_literals; + namespace KernelConsole { static int TermColors[] = { diff --git a/Kernel/core/driver/api.cpp b/Kernel/core/driver/api.cpp index a44e8741..a4bd9a97 100644 --- a/Kernel/core/driver/api.cpp +++ b/Kernel/core/driver/api.cpp @@ -273,7 +273,7 @@ namespace v0 { dbg_api("%d, %d", DriverID, Milliseconds); - TaskManager->Sleep(Milliseconds); + TaskManager->Sleep(Time::FromMilliseconds(Milliseconds)); } /* --------- */ diff --git a/Kernel/core/lock.cpp b/Kernel/core/lock.cpp index 647c1e20..1f7baf79 100644 --- a/Kernel/core/lock.cpp +++ b/Kernel/core/lock.cpp @@ -195,7 +195,7 @@ void LockClass::TimeoutDeadLock(SpinLockData &Lock, uint64_t Timeout) if (CoreData != nullptr) CCore = CoreData->ID; - uint64_t Counter = TimeManager->GetCounter(); + uint64_t Counter = TimeManager->GetTimeNs(); warn("Potential deadlock in lock '%s' held by '%s'! %ld %s in queue. Interrupts are %s. Core %ld held by %ld. Timeout in %ld (%ld ticks remaining).", Lock.AttemptingToGet, Lock.CurrentHolder, Lock.Count, Lock.Count > 1 ? "locks" : "lock", @@ -235,8 +235,7 @@ Retry: if (i >= DEADLOCK_TIMEOUT) { if (Target.load() == 0) - Target.store(TimeManager->CalculateTarget(Timeout, - Time::Units::Milliseconds)); + Target.store(TimeManager->GetTimeNs() + Timeout); TimeoutDeadLock(LockData, Target.load()); goto Retry; } diff --git a/Kernel/core/panic/kbd/xhci.cpp b/Kernel/core/panic/kbd/xhci.cpp index 7e8177cd..f2e8a62d 100644 --- a/Kernel/core/panic/kbd/xhci.cpp +++ b/Kernel/core/panic/kbd/xhci.cpp @@ -58,7 +58,7 @@ nsa bool CrashXHCIKeyboardDriver::TakeOwnership() return true; exCap->USBLEGSUP.OSOwnsHC = 1; - TimeManager->Sleep(200, Time::Milliseconds); + TimeManager->Sleep(Time::FromMilliseconds(200)); if (exCap->USBLEGSUP.BIOSOwnsHC == 0) return true; diff --git a/Kernel/core/syscalls.cpp b/Kernel/core/syscalls.cpp index 28496fe9..5c0ac92b 100644 --- a/Kernel/core/syscalls.cpp +++ b/Kernel/core/syscalls.cpp @@ -59,7 +59,7 @@ extern "C" uintptr_t SystemCallsHandler(SyscallsFrame *Frame) and switch back when this function returns. */ AutoSwitchPageTable PageSwitcher; - uint64_t _ctime = TimeManager->GetCounter(); + uint64_t _ctime = TimeManager->GetTimeNs(); Tasking::TaskInfo *Ptinfo = &thisProcess->Info; Tasking::TaskInfo *Ttinfo = &thisThread->Info; uintptr_t ret; @@ -97,7 +97,7 @@ extern "C" uintptr_t SystemCallsHandler(SyscallsFrame *Frame) } Ret: - Ptinfo->KernelTime += TimeManager->GetCounter() - _ctime; - Ttinfo->KernelTime += TimeManager->GetCounter() - _ctime; + Ptinfo->KernelTime += TimeManager->GetTimeNs() - _ctime; + Ttinfo->KernelTime += TimeManager->GetTimeNs() - _ctime; return ret; } diff --git a/Kernel/core/time/hpet.cpp b/Kernel/core/time/hpet.cpp deleted file mode 100644 index 36991a70..00000000 --- a/Kernel/core/time/hpet.cpp +++ /dev/null @@ -1,111 +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 -#include - -#include "../../kernel.h" - -namespace Time -{ - bool HighPrecisionEventTimer::Sleep(size_t Duration, Units Unit) - { -#if defined(__amd64__) - uint64_t Target = mminq(&hpet->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk; - while (mminq(&hpet->MainCounterValue) < Target) - CPU::Pause(); - return true; -#elif defined(__i386__) - uint64_t Target = mminl(&hpet->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk; - while (mminl(&hpet->MainCounterValue) < Target) - CPU::Pause(); - return true; -#endif - return false; - } - - uint64_t HighPrecisionEventTimer::GetCounter() - { -#if defined(__amd64__) - return mminq(&hpet->MainCounterValue); -#elif defined(__i386__) - return mminl(&hpet->MainCounterValue); -#else - return 0; -#endif - } - - uint64_t HighPrecisionEventTimer::CalculateTarget(uint64_t Target, Units Unit) - { -#if defined(__amd64__) - return mminq(&hpet->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk; -#elif defined(__i386__) - return mminl(&hpet->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk; -#else - return 0; -#endif - } - - uint64_t HighPrecisionEventTimer::GetNanosecondsSinceClassCreation() - { -#if defined(__amd64__) || defined(__i386__) - uint64_t Subtraction = this->GetCounter() - this->ClassCreationTime; - if (Subtraction <= 0 || this->clk <= 0) - return 0; - - Subtraction *= ConvertUnit(Units::Nanoseconds); - return uint64_t(Subtraction / this->clk); -#else - return 0; -#endif - } - - HighPrecisionEventTimer::HighPrecisionEventTimer(void *hpet) - { -#if defined(__amd64__) || defined(__i386__) - ACPI::ACPI::HPETHeader *HPET_HDR = (ACPI::ACPI::HPETHeader *)hpet; - Memory::Virtual vmm; - vmm.Map((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, (uint64_t)this->hpet->GeneralCapabilities >> 32); - KPrint("HPET clock is %u Hz", clk); -#ifdef __amd64__ - mmoutq(&this->hpet->GeneralConfiguration, 0); - mmoutq(&this->hpet->MainCounterValue, 0); - mmoutq(&this->hpet->GeneralConfiguration, 1); -#else - mmoutl(&this->hpet->GeneralConfiguration, 0); - mmoutl(&this->hpet->MainCounterValue, 0); - mmoutl(&this->hpet->GeneralConfiguration, 1); -#endif - ClassCreationTime = this->GetCounter(); -#endif - } - - HighPrecisionEventTimer::~HighPrecisionEventTimer() - { - } -} diff --git a/Kernel/core/time/timer.cpp b/Kernel/core/time/timer.cpp deleted file mode 100644 index 7b78150e..00000000 --- a/Kernel/core/time/timer.cpp +++ /dev/null @@ -1,208 +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 -#include - - -#include "../../kernel.h" - -namespace Time -{ - bool time::Sleep(size_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 this->hpet->Sleep(Duration, Unit); - case ACPI: - fixme("ACPI sleep not implemented"); - return false; - case APIC: - fixme("APIC sleep not implemented"); - return false; - case TSC: - return this->tsc->Sleep(Duration, Unit); - default: - error("Unknown timer"); - return false; - } - } - - uint64_t time::GetCounter() - { - switch (ActiveTimer) - { - case NONE: - error("No timer is active"); - return 0; - case RTC: - fixme("RTC sleep not implemented"); - return 0; - case PIT: - fixme("PIT sleep not implemented"); - return 0; - case HPET: - return this->hpet->GetCounter(); - case ACPI: - fixme("ACPI sleep not implemented"); - return 0; - case APIC: - fixme("APIC sleep not implemented"); - return 0; - case TSC: - return this->tsc->GetCounter(); - default: - error("Unknown timer"); - return 0; - } - } - - uint64_t time::CalculateTarget(uint64_t Target, Units Unit) - { - switch (ActiveTimer) - { - case NONE: - error("No timer is active"); - return 0; - case RTC: - fixme("RTC sleep not implemented"); - return 0; - case PIT: - fixme("PIT sleep not implemented"); - return 0; - case HPET: - return this->hpet->CalculateTarget(Target, Unit); - case ACPI: - fixme("ACPI sleep not implemented"); - return 0; - case APIC: - fixme("APIC sleep not implemented"); - return 0; - case TSC: - return this->tsc->CalculateTarget(Target, Unit); - default: - error("Unknown timer"); - return 0; - } - } - - uint64_t time::GetNanosecondsSinceClassCreation() - { - switch (ActiveTimer) - { - case NONE: - error("No timer is active"); - return 0; - case RTC: - fixme("RTC sleep not implemented"); - return 0; - case PIT: - fixme("PIT sleep not implemented"); - return 0; - case HPET: - return this->hpet->GetNanosecondsSinceClassCreation(); - case ACPI: - fixme("ACPI sleep not implemented"); - return 0; - case APIC: - fixme("APIC sleep not implemented"); - return 0; - case TSC: - return this->tsc->GetNanosecondsSinceClassCreation(); - default: - error("Unknown timer"); - return 0; - } - } - - void time::FindTimers(void *acpi) - { -#if defined(__amd64__) || defined(__i386__) - /* TODO: RTC check */ - /* TODO: PIT check */ - - if (acpi) - { - if (((ACPI::ACPI *)acpi)->HPET) - { - hpet = new HighPrecisionEventTimer(((ACPI::ACPI *)acpi)->HPET); - ActiveTimer = HPET; - SupportedTimers |= HPET; - KPrint("HPET found"); - } - else - { - KPrint("\x1b[33mHPET not found"); - } - - /* TODO: ACPI check */ - /* TODO: APIC check */ - } - else - { - KPrint("\x1b[33mACPI not found"); - } - - bool TSCInvariant = false; - if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) - { - CPU::x86::AMD::CPUID0x80000007 cpuid80000007; - if (cpuid80000007.EDX.TscInvariant) - TSCInvariant = true; - } - else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0) - { - // TODO: Intel 0x80000007 - CPU::x86::AMD::CPUID0x80000007 cpuid80000007; - if (cpuid80000007.EDX.TscInvariant) - TSCInvariant = true; - } - - if (TSCInvariant) - { - tsc = new TimeStampCounter; - // FIXME: ActiveTimer = TSC; - SupportedTimers |= TSC; - KPrint("Invariant TSC found"); - } - else - KPrint("\x1b[33mTSC is not invariant"); -#endif - } - - time::time() - { - } - - time::~time() - { - } -} diff --git a/Kernel/core/time/tsc.cpp b/Kernel/core/time/tsc.cpp deleted file mode 100644 index c860d8cf..00000000 --- a/Kernel/core/time/tsc.cpp +++ /dev/null @@ -1,84 +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 -#include - -#include "../../kernel.h" - -namespace Time -{ - bool TimeStampCounter::Sleep(size_t Duration, Units Unit) - { -#if defined(__amd64__) || defined(__i386__) - uint64_t Target = this->GetCounter() + (Duration * ConvertUnit(Unit)) / this->clk; - while (this->GetCounter() < Target) - CPU::Pause(); - return true; -#elif defined(__aarch64__) - return 0; -#endif - } - - uint64_t TimeStampCounter::GetCounter() - { -#if defined(__amd64__) || defined(__i386__) - return CPU::Counter(); -#elif defined(__aarch64__) - return 0; -#endif - } - - uint64_t TimeStampCounter::CalculateTarget(uint64_t Target, Units Unit) - { -#if defined(__amd64__) || defined(__i386__) - return uint64_t((this->GetCounter() + (Target * ConvertUnit(Unit))) / this->clk); -#elif defined(__aarch64__) - return 0; -#endif - } - - uint64_t TimeStampCounter::GetNanosecondsSinceClassCreation() - { -#if defined(__amd64__) || defined(__i386__) - return uint64_t((this->GetCounter() - this->ClassCreationTime) / this->clk); -#elif defined(__aarch64__) - return 0; -#endif - } - - TimeStampCounter::TimeStampCounter() - { -#if defined(__amd64__) || defined(__i386__) - stub; // 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/Kernel/include/task.hpp b/Kernel/include/task.hpp index 02dda6b1..16571209 100644 --- a/Kernel/include/task.hpp +++ b/Kernel/include/task.hpp @@ -626,11 +626,11 @@ namespace Tasking void WaitForThreadStatus(TCB *tcb, TaskState State); /** - * Sleep for a given amount of milliseconds + * Sleep for a given amount of nenoseconds * - * @param Milliseconds Amount of milliseconds to sleep + * @param Nanoseconds Amount of nenoseconds to sleep */ - void Sleep(uint64_t Milliseconds, bool NoSwitch = false); + void Sleep(uint64_t Nanoseconds, bool NoSwitch = false); PCB *CreateProcess(PCB *Parent, const char *Name, diff --git a/Kernel/include/time.hpp b/Kernel/include/time.hpp index 59fea95d..93936ab9 100644 --- a/Kernel/include/time.hpp +++ b/Kernel/include/time.hpp @@ -21,9 +21,24 @@ #include #include #include +#include namespace Time { + class ITimer + { + protected: + uint64_t ClassCreationTime = 0; + + public: + virtual const char *Name() const = 0; + virtual bool IsAvailable() const = 0; + virtual bool SupportsNanoseconds() const = 0; + virtual bool Sleep(uint64_t Nanoseconds) = 0; + virtual uint64_t GetNanoseconds() = 0; + virtual ~ITimer() = default; + }; + struct Clock { int Year, Month, Day, Hour, Minute, Second; @@ -33,138 +48,148 @@ namespace Time Clock ReadClock(); Clock ConvertFromUnix(int Timestamp); - enum Units + inline uint64_t FromSeconds(uint64_t Seconds) { return Seconds * 1'000'000'000ULL; } + inline uint64_t FromMilliseconds(uint64_t Milliseconds) { return Milliseconds * 1'000'000ULL; } + + inline uint64_t ToSeconds(uint64_t Nanoseconds) { return Nanoseconds / 1'000'000'000ULL; } + inline uint64_t ToMilliseconds(uint64_t Nanoseconds) { return Nanoseconds / 1'000'000ULL; } + + class ProgrammableIntervalTimer : public ITimer { - Femtoseconds, - Picoseconds, - Nanoseconds, - Microseconds, - Milliseconds, - Seconds, - Minutes, - Hours, - Days, - Months, - Years + public: + const char *Name() const override { return "PIT"; } + bool IsAvailable() const override; + bool SupportsNanoseconds() const override { return false; } + + bool Sleep(uint64_t Nanoseconds) override; + uint64_t GetNanoseconds() override { return 0; } + + ProgrammableIntervalTimer(); + ~ProgrammableIntervalTimer(); }; - /** @deprecated this shouldn't be used */ - inline uint64_t ConvertUnit(const Units Unit) + class RealTimeClock : public ITimer { - 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: - assert(!"Invalid time unit"); - } - } + public: + const char *Name() const override { return "RTC"; } + bool IsAvailable() const override; + bool SupportsNanoseconds() const override { return false; } - class HighPrecisionEventTimer + bool Sleep(uint64_t Nanoseconds) override; + uint64_t GetNanoseconds() override { return 0; } + + RealTimeClock(); + ~RealTimeClock(); + }; + + class HighPrecisionEventTimer : public ITimer { private: struct HPET { - uint64_t GeneralCapabilities; - uint64_t Reserved0; - uint64_t GeneralConfiguration; - uint64_t Reserved1; - uint64_t GeneralIntStatus; - uint64_t Reserved2; - uint64_t Reserved3[24]; - uint64_t MainCounterValue; - uint64_t Reserved4; + uint64_t CapabilitiesID; + uint64_t __reserved0; + uint64_t Configuration; + uint64_t __reserved1; + uint64_t InterruptStatus; + uint64_t __reserved2[25]; + uint64_t MainCounter; + uint64_t __reserved3; }; - uint32_t clk = 0; + uint64_t Period = 0; HPET *hpet = nullptr; - uint64_t ClassCreationTime = 0; public: - bool Sleep(size_t Duration, Units Unit); - uint64_t GetCounter(); - uint64_t CalculateTarget(uint64_t Target, Units Unit); - uint64_t GetNanosecondsSinceClassCreation(); + const char *Name() const override { return "HPET"; } + bool IsAvailable() const override { return hpet != nullptr; } + bool SupportsNanoseconds() const override { return true; } + bool Sleep(uint64_t Nanoseconds) override; + uint64_t GetNanoseconds() override; HighPrecisionEventTimer(void *hpet); ~HighPrecisionEventTimer(); }; - class TimeStampCounter + class TimeStampCounter : public ITimer { private: uint64_t clk = 0; - uint64_t ClassCreationTime = 0; public: - bool Sleep(size_t Duration, Units Unit); - uint64_t GetCounter(); - uint64_t CalculateTarget(uint64_t Target, Units Unit); - uint64_t GetNanosecondsSinceClassCreation(); + const char *Name() const override { return "TSC"; } + bool IsAvailable() const override { return clk != 0; } + bool SupportsNanoseconds() const override { return true; } + bool Sleep(uint64_t Nanoseconds) override; + uint64_t GetNanoseconds() override; TimeStampCounter(); - ~TimeStampCounter(); + ~TimeStampCounter() = default; }; - class time + class KVMClock : public ITimer { - public: - enum TimeActiveTimer + private: + struct kvm_clock_pairing { - NONE = 0b0, - RTC = 0b1, - PIT = 0b10, - HPET = 0b100, - ACPI = 0b1000, - APIC = 0b10000, - TSC = 0b100000 + int64_t sec; + int64_t nsec; + uint64_t tsc; + uint32_t flags; + uint32_t pad[9]; }; - private: - int SupportedTimers = 0; - TimeActiveTimer ActiveTimer = NONE; + struct pvclock_vcpu_time_info + { + uint32_t version; + uint32_t pad0; + uint64_t tsc_timestamp; + uint64_t system_time; + uint32_t tsc_to_system_mul; + int8_t tsc_shift; + uint8_t flags; + uint8_t pad[2]; + }; - HighPrecisionEventTimer *hpet; - TimeStampCounter *tsc; + struct ms_hyperv_tsc_page + { + volatile uint32_t tsc_sequence; + uint32_t reserved1; + volatile uint64_t tsc_scale; + volatile int64_t tsc_offset; + uint64_t reserved2[509]; + }; + + uint64_t clk = 0; + kvm_clock_pairing *Pairing = nullptr; public: - int GetSupportedTimers() { return SupportedTimers; } - TimeActiveTimer GetActiveTimer() { return ActiveTimer; } - bool ChangeActiveTimer(TimeActiveTimer Timer) - { - if (!(SupportedTimers & Timer)) - return false; - ActiveTimer = Timer; - return true; - } + const char *Name() const override { return "KVM"; } + bool IsAvailable() const override { return clk != 0; } + bool SupportsNanoseconds() const override { return true; } + bool Sleep(uint64_t Nanoseconds) override; + uint64_t GetNanoseconds() override; - bool Sleep(size_t Duration, Units Unit); - uint64_t GetCounter(); - uint64_t CalculateTarget(uint64_t Target, Units Unit); - uint64_t GetNanosecondsSinceClassCreation(); - void FindTimers(void *acpi); - time(); - ~time(); + KVMClock(); + ~KVMClock(); + }; + + class Manager + { + private: + void *acpi = nullptr; + std::vector Timers; + int ActiveTimer = -1; + + public: + void CheckActiveTimer(); + bool Sleep(uint64_t Nanoseconds); + uint64_t GetTimeNs(); + const char *GetActiveTimerName(); + + void InitializeTimers(); + Manager(void *acpi); + ~Manager() = delete; }; } diff --git a/Kernel/kernel.cpp b/Kernel/kernel.cpp index 09a6244c..03eaa420 100644 --- a/Kernel/kernel.cpp +++ b/Kernel/kernel.cpp @@ -57,7 +57,7 @@ struct KernelConfig Config = { Video::Display *Display = nullptr; SymbolResolver::Symbols *KernelSymbolTable = nullptr; Power::Power *PowerManager = nullptr; -Time::time *TimeManager = nullptr; +Time::Manager *TimeManager = nullptr; Tasking::Task *TaskManager = nullptr; PCI::Manager *PCIManager = nullptr; Driver::Manager *DriverManager = nullptr; @@ -76,14 +76,14 @@ EXTERNC void _KPrint(const char *Format, va_list Args) { SmartLock(KernelLock); - uint64_t nano = TimeManager ? TimeManager->GetNanosecondsSinceClassCreation() : 0; + uint64_t nano = TimeManager ? TimeManager->GetTimeNs() : 0; #if defined(__amd64__) - printf("\x1b[1;30m[\x1b[1;34m%lu.%07lu\x1b[1;30m]\x1b[0m ", nano / 10000000, nano % 10000000); + printf("\x1b[1;30m[\x1b[1;34m%lu.%07lu\x1b[1;30m]\x1b[0m ", Time::ToSeconds(nano), nano % 10000000); #elif defined(__i386__) - printf("\x1b[1;30m[\x1b[1;34m%llu.%07llu\x1b[1;30m]\x1b[0m ", nano / 10000000, nano % 10000000); + printf("\x1b[1;30m[\x1b[1;34m%llu.%07llu\x1b[1;30m]\x1b[0m ", Time::ToSeconds(nano), nano % 10000000); #elif defined(__aarch64__) - printf("\x1b[1;30m[\x1b[1;34m%lu.%07lu\x1b[1;30m]\x1b[0m ", nano / 10000000, nano % 10000000); + printf("\x1b[1;30m[\x1b[1;34m%lu.%07lu\x1b[1;30m]\x1b[0m ", Time::ToSeconds(nano), nano % 10000000); #endif vprintf(Format, Args); @@ -232,8 +232,8 @@ EXTERNC nif cold void Main() #endif KPrint("Initializing Timers"); - TimeManager = new Time::time; - TimeManager->FindTimers(PowerManager->GetACPI()); + TimeManager = new Time::Manager(PowerManager->GetACPI()); + TimeManager->InitializeTimers(); KPrint("Initializing PCI Manager"); PCIManager = new PCI::Manager; @@ -388,12 +388,6 @@ EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot) if (fs) delete fs, fs = nullptr; - KPrint("Stopping timers"); - if (TimeManager) - delete TimeManager, TimeManager = nullptr; - - // PowerManager should not be called - // https://wiki.osdev.org/Calling_Global_Constructors KPrint("Calling destructors"); for (CallPtr *fct = __fini_array_start; fct != __fini_array_end; fct++) diff --git a/Kernel/kernel.h b/Kernel/kernel.h index 2e8d54e7..6162c16f 100644 --- a/Kernel/kernel.h +++ b/Kernel/kernel.h @@ -48,7 +48,7 @@ extern bool DebuggerIsAttached; extern Video::Display *Display; extern SymbolResolver::Symbols *KernelSymbolTable; extern Power::Power *PowerManager; -extern Time::time *TimeManager; +extern Time::Manager *TimeManager; extern PCI::Manager *PCIManager; extern vfs::Virtual *fs; extern Tasking::Task *TaskManager; diff --git a/Kernel/kernel_thread.cpp b/Kernel/kernel_thread.cpp index be496881..00b3ad16 100644 --- a/Kernel/kernel_thread.cpp +++ b/Kernel/kernel_thread.cpp @@ -169,7 +169,7 @@ Exit: ExitCode, ExitCode < 0 ? -ExitCode : ExitCode); KPrint("Dropping to kernel shell"); - TaskManager->Sleep(1000); + TaskManager->Sleep(Time::FromMilliseconds(1000)); TaskManager->CreateThread(thisProcess, Tasking::IP(KShellThread))->Rename("Kernel Shell"); CPU::Halt(true); } diff --git a/Kernel/kshell/commands/uptime.cpp b/Kernel/kshell/commands/uptime.cpp index 718c2131..9fa97499 100644 --- a/Kernel/kshell/commands/uptime.cpp +++ b/Kernel/kshell/commands/uptime.cpp @@ -28,7 +28,7 @@ void cmd_uptime(const char *) if (TimeManager) { uint64_t Nanoseconds = - TimeManager->GetNanosecondsSinceClassCreation(); + TimeManager->GetTimeNs(); uint64_t Seconds = Nanoseconds / 10000000; uint64_t Minutes = Seconds / 60; uint64_t Hours = Minutes / 60; diff --git a/Kernel/subsystem/linux/syscall.cpp b/Kernel/subsystem/linux/syscall.cpp index 9d4804a1..f98868f0 100644 --- a/Kernel/subsystem/linux/syscall.cpp +++ b/Kernel/subsystem/linux/syscall.cpp @@ -1389,10 +1389,10 @@ static int linux_nanosleep(SysFrm *, pReq->tv_nsec, pReq->tv_sec); uint64_t nanoTime = pReq->tv_nsec; - uint64_t secTime = pReq->tv_sec * 1000000000; /* Nano */ + uint64_t secTime = Time::FromSeconds(pReq->tv_sec); - uint64_t time = TimeManager->GetCounter(); - uint64_t sleepTime = TimeManager->CalculateTarget(nanoTime + secTime, Time::Nanoseconds); + uint64_t time = TimeManager->GetTimeNs(); + uint64_t sleepTime = TimeManager->GetTimeNs() + secTime + nanoTime; debug("time=%ld secTime=%ld nanoTime=%ld sleepTime=%ld", time, secTime, nanoTime, sleepTime); @@ -1406,7 +1406,7 @@ static int linux_nanosleep(SysFrm *, } pcb->GetContext()->Yield(); - time = TimeManager->GetCounter(); + time = TimeManager->GetTimeNs(); } debug("time= %ld", time); debug("sleepTime=%ld", sleepTime); @@ -2582,7 +2582,7 @@ static int linux_sysinfo(SysFrm *, struct sysinfo *info) if (pInfo == nullptr) return -linux_EFAULT; - uint64_t nano = TimeManager->GetNanosecondsSinceClassCreation(); + uint64_t nano = TimeManager->GetTimeNs(); if (nano != 0) nano /= 10000000; @@ -3185,18 +3185,18 @@ static int linux_clock_gettime(SysFrm *, clockid_t clockid, struct timespec *tp) { case linux_CLOCK_REALTIME: { - uint64_t time = TimeManager->GetCounter(); - pTp->tv_sec = time / Time::ConvertUnit(Time::Seconds); - pTp->tv_nsec = time / Time::ConvertUnit(Time::Nanoseconds); + uint64_t time = TimeManager->GetTimeNs(); + pTp->tv_sec = Time::ToSeconds(time); + pTp->tv_nsec = time; debug("time=%ld sec=%ld nsec=%ld", time, pTp->tv_sec, pTp->tv_nsec); break; } case linux_CLOCK_MONOTONIC: { - uint64_t time = TimeManager->GetCounter(); - pTp->tv_sec = time / Time::ConvertUnit(Time::Seconds); - pTp->tv_nsec = time / Time::ConvertUnit(Time::Nanoseconds); + uint64_t time = TimeManager->GetTimeNs(); + pTp->tv_sec = Time::ToSeconds(time); + pTp->tv_nsec = time; debug("time=%ld sec=%ld nsec=%ld", time, pTp->tv_sec, pTp->tv_nsec); break; @@ -3244,9 +3244,8 @@ static int linux_clock_nanosleep(SysFrm *, clockid_t clockid, int flags, case linux_CLOCK_REALTIME: case linux_CLOCK_MONOTONIC: { - uint64_t time = TimeManager->GetCounter(); - uint64_t rqTime = pRequest->tv_sec * Time::ConvertUnit(Time::Seconds) + - pRequest->tv_nsec * Time::ConvertUnit(Time::Nanoseconds); + uint64_t time = TimeManager->GetTimeNs(); + uint64_t rqTime = Time::FromSeconds(pRequest->tv_sec) + pRequest->tv_nsec; debug("Sleeping for %ld", rqTime - time); if (rqTime > time) diff --git a/Kernel/subsystem/time/hpet.cpp b/Kernel/subsystem/time/hpet.cpp new file mode 100644 index 00000000..c1aca55b --- /dev/null +++ b/Kernel/subsystem/time/hpet.cpp @@ -0,0 +1,100 @@ +/* + 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 +#include + +#include "../../kernel.h" + +namespace Time +{ + bool HighPrecisionEventTimer::Sleep(size_t Nanoseconds) + { + uint64_t target = this->GetNanoseconds() + Nanoseconds; + while (this->GetNanoseconds() < target) + CPU::Pause(); + return true; + } + + uint64_t HighPrecisionEventTimer::GetNanoseconds() + { +#if defined(__amd64__) + uint64_t counter = mminq(&this->hpet->MainCounter); +#elif defined(__i386__) + uint64_t counter = mminl(&this->hpet->MainCounter); +#else + return 0; +#endif + /* convert ticks to nanoseconds: counter * period_fs / 1e6 */ + return (counter * 1'000'000'000ULL) / this->Period; + } + + HighPrecisionEventTimer::HighPrecisionEventTimer(void *hpet) + { +#if defined(__amd64__) || defined(__i386__) + ACPI::ACPI::HPETHeader *hdr = (ACPI::ACPI::HPETHeader *)hpet; + Memory::Virtual vmm; + vmm.Map((void *)hdr->Address.Address, (void *)hdr->Address.Address, Memory::RW | Memory::PCD | Memory::PWT); + this->hpet = reinterpret_cast(hdr->Address.Address); + debug("%s timer is at address %#lx", hdr->Header.OEMID, hdr->Address.Address); + uint64_t period_fs = this->hpet->CapabilitiesID >> 32; + if (period_fs == 0) + { + warn("HPET: Invalid period in CapabilitiesID"); + return; + } + + /* Hz = 1e15 / period_fs */ + this->Period = 1'000'000'000'000'000ULL / period_fs; + KPrint("HPET tick period: %lu femtoseconds -> %u Hz", period_fs, this->Period); +#ifdef __amd64__ + mmoutq(&this->hpet->Configuration, 0); + mmoutq(&this->hpet->MainCounter, 0); + mmoutq(&this->hpet->Configuration, 1); +#else + mmoutl(&this->hpet->Configuration, 0); + mmoutl(&this->hpet->MainCounter, 0); + mmoutl(&this->hpet->Configuration, 1); +#endif + + for (int i = 0; i < 5; i++) + { + uint64_t val = mminq(&this->hpet->MainCounter); + KPrint("HPET counter test %d: %llu", i, val); + } + + uint64_t cfg = mminq(&this->hpet->Configuration); + if (!(cfg & 1)) + warn("HPET counter is not enabled!"); + + ClassCreationTime = this->GetNanoseconds(); +#endif + } + + HighPrecisionEventTimer::~HighPrecisionEventTimer() + { +#ifdef __amd64__ + mmoutq(&this->hpet->Configuration, 0); +#else + mmoutl(&this->hpet->Configuration, 0); +#endif + } +} diff --git a/Kernel/subsystem/time/kvm_clock.cpp b/Kernel/subsystem/time/kvm_clock.cpp new file mode 100644 index 00000000..f445c3e3 --- /dev/null +++ b/Kernel/subsystem/time/kvm_clock.cpp @@ -0,0 +1,71 @@ +/* + 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 +#include + +#include "../../kernel.h" + +#define KVM_CLOCK_PAIRING_WALLCLOCK 0 + +namespace Time +{ + extern "C" void kvm_hc_clock_pairing(uint64_t phys_addr, uint64_t clock_type) + { +#if defined(__amd64__) + asm volatile( + "mov $9, %%eax\n\t" /* KVM_HC_CLOCK_PAIRING */ + "mov %%rdi, %%rbx\n\t" + "mov %%rsi, %%rcx\n\t" + "vmcall\n\t" + : + : "D"(phys_addr), "S"(clock_type) + : "rax", "rbx", "rcx"); +#else +#warning "KVM clock pairing not implemented for this architecture" +#endif + } + + bool KVMClock::Sleep(uint64_t Nanoseconds) + { + return true; + } + + uint64_t KVMClock::GetNanoseconds() + { + return 0; + } + + KVMClock::KVMClock() + { + if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_KVM) != 0) + return; + + this->Pairing = (kvm_clock_pairing *)KernelAllocator.RequestPages(TO_PAGES(sizeof(kvm_clock_pairing))); + kvm_hc_clock_pairing((uint64_t)this->Pairing, KVM_CLOCK_PAIRING_WALLCLOCK); + // KPrint("sec: %lld, nsec: %lld, tsc: %lld", this->Pairing->sec, this->Pairing->nsec, this->Pairing->tsc); + // KPrint("flags: %x", this->Pairing->flags); + } + + KVMClock::~KVMClock() + { + } +} diff --git a/Kernel/subsystem/time/manager.cpp b/Kernel/subsystem/time/manager.cpp new file mode 100644 index 00000000..6c1a9674 --- /dev/null +++ b/Kernel/subsystem/time/manager.cpp @@ -0,0 +1,107 @@ +/* + 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 +#include + +#include "../../kernel.h" + +namespace Time +{ + void Manager::CheckActiveTimer() + { + if (unlikely(Timers[ActiveTimer]->IsAvailable() == false)) + { + for (size_t i = Timers.size(); i-- > 0;) + { + if (Timers[i]->IsAvailable() == false) + continue; + ActiveTimer = i; + break; + } + } + } + + bool Manager::Sleep(size_t Nanoseconds) + { + if (unlikely(Timers.empty())) + return false; + + this->CheckActiveTimer(); + debug("sleep for %d ns in timer %s", Nanoseconds, Timers[ActiveTimer]->Name()); + return Timers[ActiveTimer]->Sleep(Nanoseconds); + } + + uint64_t Manager::GetTimeNs() + { + if (unlikely(Timers.empty())) + return 0; + + this->CheckActiveTimer(); + return Timers[ActiveTimer]->GetNanoseconds(); + } + + const char *Manager::GetActiveTimerName() + { + if (unlikely(Timers.empty())) + return "\0"; + + this->CheckActiveTimer(); + return Timers[ActiveTimer]->Name(); + } + + void Manager::InitializeTimers() + { +#if defined(__amd64__) || defined(__i386__) + /* TODO: RTC check */ + /* TODO: PIT check */ + + if (acpi) + { + if (((ACPI::ACPI *)acpi)->HPET) + { + ITimer *hpet = new HighPrecisionEventTimer(((ACPI::ACPI *)acpi)->HPET); + ActiveTimer = Timers.size(); + Timers.push_back(hpet); + } + + /* TODO: ACPI check */ + /* TODO: APIC check */ + } + else + { + KPrint("\x1b[33mACPI not available"); + } + + ITimer *tsc = new TimeStampCounter; + ActiveTimer = Timers.size(); + Timers.push_back(tsc); + + ITimer *kvmclock = new KVMClock; + ActiveTimer = Timers.size(); + Timers.push_back(kvmclock); +#endif + + assert(Timers.empty() == false); + } + + Manager::Manager(void *_acpi) : acpi(_acpi) {} +} diff --git a/Kernel/core/time/time.cpp b/Kernel/subsystem/time/rtc.cpp similarity index 100% rename from Kernel/core/time/time.cpp rename to Kernel/subsystem/time/rtc.cpp diff --git a/Kernel/subsystem/time/tsc.cpp b/Kernel/subsystem/time/tsc.cpp new file mode 100644 index 00000000..83025978 --- /dev/null +++ b/Kernel/subsystem/time/tsc.cpp @@ -0,0 +1,105 @@ +/* + 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 +#include + +#include "../../kernel.h" + +namespace Time +{ + static inline uint64_t rdtsc() + { +#if defined(__amd64__) || defined(__i386__) + unsigned int lo, hi; + __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); + return ((uint64_t)hi << 32) | lo; +#else + return 0; +#endif + } + + bool TimeStampCounter::Sleep(uint64_t Nanoseconds) + { + uint64_t target = this->GetNanoseconds() + Nanoseconds; + while (this->GetNanoseconds() < target) + CPU::Pause(); + return true; + } + + uint64_t TimeStampCounter::GetNanoseconds() + { + uint64_t tsc = rdtsc(); + return (tsc * 1000000000ULL) / this->clk; + } + + TimeStampCounter::TimeStampCounter() + { + bool TSCInvariant = false; + if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) + { + CPU::x86::AMD::CPUID0x80000007 cpuid80000007; + if (cpuid80000007.EDX.TscInvariant) + TSCInvariant = true; + } + else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0) + { + // TODO: Intel 0x80000007 + CPU::x86::AMD::CPUID0x80000007 cpuid80000007; + if (cpuid80000007.EDX.TscInvariant) + TSCInvariant = true; + } + + if (!TSCInvariant) + { + KPrint("\x1b[33mTSC is not invariant"); + return; + } + + const int attempts = 5; + uint64_t ns = 10000000ULL; /* 10 ms */ + uint64_t total_clk = 0; + uint64_t overhead = 0; + + for (int i = 0; i < attempts; ++i) + { + uint64_t t0 = rdtsc(); + uint64_t t1 = rdtsc(); + overhead += (t1 - t0); + } + overhead /= attempts; + + for (int i = 0; i < attempts; ++i) + { + uint64_t tsc_start = rdtsc(); + uint64_t hpet_start = TimeManager->GetTimeNs(); + while (TimeManager->GetTimeNs() - hpet_start < ns) + CPU::Pause(); + uint64_t tsc_end = rdtsc(); + total_clk += (tsc_end - tsc_start - overhead) * 1000000000ULL / ns; + } + this->clk = total_clk / attempts; + KPrint("TSC frequency: %lu MHz", this->clk / 1000000); + this->ClassCreationTime = this->GetNanoseconds(); + fixme("tsc not working as expected"); + this->clk = 0; /* disable */ + } +} diff --git a/Kernel/tasking/process.cpp b/Kernel/tasking/process.cpp index 7e2b530e..a58a0fae 100644 --- a/Kernel/tasking/process.cpp +++ b/Kernel/tasking/process.cpp @@ -251,7 +251,7 @@ namespace Tasking this->AllocatedMemory += sizeof(Memory::ProgramBreak); this->AllocatedMemory += sizeof(SymbolResolver::Symbols); - this->Info.SpawnTime = TimeManager->GetCounter(); + this->Info.SpawnTime = TimeManager->GetTimeNs(); if (Parent) Parent->Children.push_back(this); diff --git a/Kernel/tasking/scheduler/custom.cpp b/Kernel/tasking/scheduler/custom.cpp index 97e66198..6ccb78af 100644 --- a/Kernel/tasking/scheduler/custom.cpp +++ b/Kernel/tasking/scheduler/custom.cpp @@ -290,7 +290,7 @@ namespace Tasking::Scheduler hot nsa void Custom::UpdateUsage(TaskInfo *Info, TaskExecutionMode Mode, int Core) { UNUSED(Core); - uint64_t CurrentTime = TimeManager->GetCounter(); + uint64_t CurrentTime = TimeManager->GetTimeNs(); uint64_t TimePassed = Info->LastUpdateTime - CurrentTime; Info->LastUpdateTime = CurrentTime; @@ -529,7 +529,7 @@ namespace Tasking::Scheduler continue; /* Check if the thread is ready to wake up. */ - if (unlikely(thread->Info.SleepUntil < TimeManager->GetCounter())) + if (unlikely(thread->Info.SleepUntil < TimeManager->GetTimeNs())) { if (pState == TaskState::Sleeping) process->State.store(TaskState::Ready); @@ -541,7 +541,7 @@ namespace Tasking::Scheduler else { wut_schedbg("Thread \"%s\"(%d) is not ready to wake up. (SleepUntil: %d, Counter: %d)", - thread->Name, thread->ID, thread->Info.SleepUntil, TimeManager->GetCounter()); + thread->Name, thread->ID, thread->Info.SleepUntil, TimeManager->GetTimeNs()); } } } @@ -574,7 +574,7 @@ namespace Tasking::Scheduler return; } bool ProcessNotChanged = false; - uint64_t SchedTmpTicks = TimeManager->GetCounter(); + uint64_t SchedTmpTicks = TimeManager->GetTimeNs(); this->LastTaskTicks.store(size_t(SchedTmpTicks - this->SchedulerTicks.load())); CPUData *CurrentCPU = GetCurrentCPU(); this->LastCore.store(CurrentCPU->ID); @@ -621,7 +621,7 @@ namespace Tasking::Scheduler CurrentCPU->CurrentProcess->State.store(TaskState::Running); CurrentCPU->CurrentThread->State.store(TaskState::Running); *Frame = CurrentCPU->CurrentThread->Registers; - this->SchedulerTicks.store(size_t(TimeManager->GetCounter() - SchedTmpTicks)); + this->SchedulerTicks.store(size_t(TimeManager->GetTimeNs() - SchedTmpTicks)); return; } @@ -696,8 +696,8 @@ namespace Tasking::Scheduler CurrentCPU->CurrentProcess->Signals.HandleSignal(Frame, CurrentCPU->CurrentThread.load()); if (!ProcessNotChanged) - (&CurrentCPU->CurrentProcess->Info)->LastUpdateTime = TimeManager->GetCounter(); - (&CurrentCPU->CurrentThread->Info)->LastUpdateTime = TimeManager->GetCounter(); + (&CurrentCPU->CurrentProcess->Info)->LastUpdateTime = TimeManager->GetTimeNs(); + (&CurrentCPU->CurrentThread->Info)->LastUpdateTime = TimeManager->GetTimeNs(); this->OneShot(CurrentCPU->CurrentThread->Info.Priority); if (CurrentCPU->CurrentThread->Security.IsDebugEnabled && @@ -720,7 +720,7 @@ namespace Tasking::Scheduler #endif } - this->SchedulerTicks.store(size_t(TimeManager->GetCounter() - SchedTmpTicks)); + this->SchedulerTicks.store(size_t(TimeManager->GetTimeNs() - SchedTmpTicks)); } hot nsa nif void Custom::OnInterruptReceived(CPU::SchedulerFrame *Frame) @@ -754,7 +754,7 @@ namespace Tasking::Scheduler } debug("Waiting for processes to terminate"); - uint64_t timeout = TimeManager->CalculateTarget(20, Time::Units::Seconds); + uint64_t timeout = TimeManager->GetTimeNs() + Time::FromSeconds(20); while (this->GetProcessList().size() > 0) { trace("Waiting for %d processes to terminate", this->GetProcessList().size()); @@ -780,7 +780,7 @@ namespace Tasking::Scheduler ctx->GetCurrentProcess()->Name, ctx->GetCurrentProcess()->ID); - if (TimeManager->GetCounter() > timeout) + if (TimeManager->GetTimeNs() > timeout) { error("Timeout waiting for processes to terminate"); break; diff --git a/Kernel/tasking/task.cpp b/Kernel/tasking/task.cpp index 87342ec2..814c6500 100644 --- a/Kernel/tasking/task.cpp +++ b/Kernel/tasking/task.cpp @@ -167,7 +167,7 @@ namespace Tasking this->Yield(); } - void Task::Sleep(uint64_t Milliseconds, bool NoSwitch) + void Task::Sleep(uint64_t Nanoseconds, bool NoSwitch) { TCB *thread = this->GetCurrentThread(); PCB *process = thread->Parent; @@ -179,13 +179,11 @@ namespace Tasking if (process->Threads.size() == 1) process->SetState(TaskState::Sleeping); - thread->Info.SleepUntil = - TimeManager->CalculateTarget(Milliseconds, - Time::Units::Milliseconds); + thread->Info.SleepUntil = TimeManager->GetTimeNs() + Nanoseconds; } // #ifdef DEBUG - // uint64_t TicksNow = TimeManager->GetCounter(); + // uint64_t TicksNow = TimeManager->GetTimeNs(); // #endif // debug("Thread \"%s\"(%d) is going to sleep until %llu, current %llu, diff %llu", // thread->Name, thread->ID, thread->Info.SleepUntil, diff --git a/Kernel/tasking/thread.cpp b/Kernel/tasking/thread.cpp index d9eeb918..d949b1cf 100644 --- a/Kernel/tasking/thread.cpp +++ b/Kernel/tasking/thread.cpp @@ -650,7 +650,7 @@ namespace Tasking this->AllocatedMemory += strlen(this->Parent->Name) + 1; this->AllocatedMemory += sizeof(Memory::StackGuard); - this->Info.SpawnTime = TimeManager->GetCounter(); + this->Info.SpawnTime = TimeManager->GetTimeNs(); this->Parent->Threads.push_back(this); if (this->Parent->Threads.size() == 1 && diff --git a/Kernel/tests/readdir.cpp b/Kernel/tests/readdir.cpp index a9cb11b5..2c31fe9e 100644 --- a/Kernel/tests/readdir.cpp +++ b/Kernel/tests/readdir.cpp @@ -70,23 +70,23 @@ void readdir_sanity_tests() KPrint("TEST /"); TestReadDirectory(t0); - TaskManager->Sleep(2000); + TaskManager->Sleep(Time::FromMilliseconds(2000)); KPrint("TEST /dev"); TestReadDirectory(t1); - TaskManager->Sleep(2000); + TaskManager->Sleep(Time::FromMilliseconds(2000)); KPrint("TEST /home"); TestReadDirectory(t2); - TaskManager->Sleep(2000); + TaskManager->Sleep(Time::FromMilliseconds(2000)); KPrint("TEST /var"); TestReadDirectory(t3); - TaskManager->Sleep(2000); + TaskManager->Sleep(Time::FromMilliseconds(2000)); KPrint("TEST /tmp"); TestReadDirectory(t4); - TaskManager->Sleep(2000); + TaskManager->Sleep(Time::FromMilliseconds(2000)); CPU::Stop(); } diff --git a/Kernel/tests/task_heartbeat.cpp b/Kernel/tests/task_heartbeat.cpp index 13c4470d..48a58c18 100644 --- a/Kernel/tests/task_heartbeat.cpp +++ b/Kernel/tests/task_heartbeat.cpp @@ -29,7 +29,7 @@ void TaskHeartbeat() while (true) { debug("Task Heartbeat"); - TaskManager->Sleep(5000); + TaskManager->Sleep(Time::FromMilliseconds(5000)); } } diff --git a/Kernel/tests/taskmgr.cpp b/Kernel/tests/taskmgr.cpp index b2705598..32401bbf 100644 --- a/Kernel/tests/taskmgr.cpp +++ b/Kernel/tests/taskmgr.cpp @@ -67,7 +67,7 @@ void TaskMgr_Dummy100Usage() void TaskMgr_Dummy0Usage() { while (1) - TaskManager->Sleep(1000000); + TaskManager->Sleep(Time::FromMilliseconds(1000000)); } uint64_t GetUsage(uint64_t OldSystemTime, Tasking::TaskInfo *Info) @@ -75,7 +75,7 @@ uint64_t GetUsage(uint64_t OldSystemTime, Tasking::TaskInfo *Info) /* https://github.com/reactos/reactos/blob/560671a784c1e0e0aa7590df5e0598c1e2f41f5a/base/applications/taskmgr/perfdata.c#L347 */ if (Info->OldKernelTime || Info->OldUserTime) { - uint64_t SystemTime = TimeManager->GetCounter() - OldSystemTime; + uint64_t SystemTime = TimeManager->GetTimeNs() - OldSystemTime; uint64_t CurrentTime = Info->KernelTime + Info->UserTime; uint64_t OldTime = Info->OldKernelTime + Info->OldUserTime; uint64_t CpuUsage = (CurrentTime - OldTime) / SystemTime; @@ -168,7 +168,7 @@ void TaskMgr() #endif } } - OldSystemTime = TimeManager->GetCounter(); + OldSystemTime = TimeManager->GetTimeNs(); #if defined(__amd64__) register uintptr_t CurrentStackAddress asm("rsp"); printf("Sanity: %d, Stack: %#lx", sanity++, CurrentStackAddress); @@ -185,7 +185,7 @@ void TaskMgr() if (!Config.Quiet) Display->UpdateBuffer(); - TaskManager->Sleep(100); + TaskManager->Sleep(Time::FromMilliseconds(100)); } } diff --git a/Makefile b/Makefile index f98fd2fa..ea04b2f1 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ QEMUFLAGS := -display gtk ifeq ($(OSARCH), amd64) QEMUFLAGS += -device vmware-svga -M q35 \ + -cpu max \ -usb \ -device qemu-xhci,id=xhci \ -net user \ @@ -40,6 +41,7 @@ QEMUFLAGS += -device vmware-svga -M q35 \ -acpitable file=tools/acpi/SSDT1.dat else ifeq ($(OSARCH), i386) QEMUFLAGS += -M q35 \ + -cpu max \ -usb \ -device qemu-xhci,id=xhci \ -device usb-mouse,bus=xhci.0,pcap=mousex.pcap \