mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-06-07 20:27:59 +00:00
refactor(kernel): ♻️ rewrite time manager
This commit is contained in:
parent
9538589c11
commit
33c284091d
@ -442,7 +442,7 @@ namespace APIC
|
|||||||
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
|
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeManager->Sleep(1, Time::Units::Milliseconds);
|
TimeManager->Sleep(Time::FromMilliseconds(1));
|
||||||
|
|
||||||
// Mask the timer
|
// Mask the timer
|
||||||
if (this->lapic->x2APIC)
|
if (this->lapic->x2APIC)
|
||||||
|
@ -167,14 +167,14 @@ namespace SMP
|
|||||||
}
|
}
|
||||||
|
|
||||||
apic->SendInitIPI(lapic->APICId);
|
apic->SendInitIPI(lapic->APICId);
|
||||||
TimeManager->Sleep(20, Time::Units::Milliseconds);
|
TimeManager->Sleep(Time::FromMilliseconds(20));
|
||||||
apic->SendStartupIPI(lapic->APICId, TRAMPOLINE_START);
|
apic->SendStartupIPI(lapic->APICId, TRAMPOLINE_START);
|
||||||
debug("Waiting for CPU %d to load...", lapic->APICId);
|
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)
|
while (CPUEnabled.load(std::memory_order_acquire) == false)
|
||||||
{
|
{
|
||||||
if (TimeManager->GetCounter() > Timeout)
|
if (TimeManager->GetTimeNs() > Timeout)
|
||||||
{
|
{
|
||||||
error("CPU %d failed to load!", lapic->APICId);
|
error("CPU %d failed to load!", lapic->APICId);
|
||||||
KPrint("\x1b[1;37;41mCPU %d failed to load!",
|
KPrint("\x1b[1;37;41mCPU %d failed to load!",
|
||||||
|
@ -368,7 +368,7 @@ namespace APIC
|
|||||||
this->lapic->Write(APIC_TDCR, DivideBy128);
|
this->lapic->Write(APIC_TDCR, DivideBy128);
|
||||||
else
|
else
|
||||||
this->lapic->Write(APIC_TDCR, DivideBy16);
|
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));
|
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_TDCR, Divider);
|
||||||
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
|
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
|
||||||
|
|
||||||
TimeManager->Sleep(1, Time::Units::Milliseconds);
|
TimeManager->Sleep(Time::FromMilliseconds(1));
|
||||||
|
|
||||||
// Mask the timer
|
// Mask the timer
|
||||||
this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */);
|
this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */);
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#include "../kernel.h"
|
#include "../kernel.h"
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
namespace KernelConsole
|
namespace KernelConsole
|
||||||
{
|
{
|
||||||
static int TermColors[] = {
|
static int TermColors[] = {
|
||||||
|
@ -273,7 +273,7 @@ namespace v0
|
|||||||
{
|
{
|
||||||
dbg_api("%d, %d", DriverID, Milliseconds);
|
dbg_api("%d, %d", DriverID, Milliseconds);
|
||||||
|
|
||||||
TaskManager->Sleep(Milliseconds);
|
TaskManager->Sleep(Time::FromMilliseconds(Milliseconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------- */
|
/* --------- */
|
||||||
|
@ -195,7 +195,7 @@ void LockClass::TimeoutDeadLock(SpinLockData &Lock, uint64_t Timeout)
|
|||||||
if (CoreData != nullptr)
|
if (CoreData != nullptr)
|
||||||
CCore = CoreData->ID;
|
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).",
|
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",
|
Lock.AttemptingToGet, Lock.CurrentHolder, Lock.Count, Lock.Count > 1 ? "locks" : "lock",
|
||||||
@ -235,8 +235,7 @@ Retry:
|
|||||||
if (i >= DEADLOCK_TIMEOUT)
|
if (i >= DEADLOCK_TIMEOUT)
|
||||||
{
|
{
|
||||||
if (Target.load() == 0)
|
if (Target.load() == 0)
|
||||||
Target.store(TimeManager->CalculateTarget(Timeout,
|
Target.store(TimeManager->GetTimeNs() + Timeout);
|
||||||
Time::Units::Milliseconds));
|
|
||||||
TimeoutDeadLock(LockData, Target.load());
|
TimeoutDeadLock(LockData, Target.load());
|
||||||
goto Retry;
|
goto Retry;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ nsa bool CrashXHCIKeyboardDriver::TakeOwnership()
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
exCap->USBLEGSUP.OSOwnsHC = 1;
|
exCap->USBLEGSUP.OSOwnsHC = 1;
|
||||||
TimeManager->Sleep(200, Time::Milliseconds);
|
TimeManager->Sleep(Time::FromMilliseconds(200));
|
||||||
if (exCap->USBLEGSUP.BIOSOwnsHC == 0)
|
if (exCap->USBLEGSUP.BIOSOwnsHC == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ extern "C" uintptr_t SystemCallsHandler(SyscallsFrame *Frame)
|
|||||||
and switch back when this function returns. */
|
and switch back when this function returns. */
|
||||||
AutoSwitchPageTable PageSwitcher;
|
AutoSwitchPageTable PageSwitcher;
|
||||||
|
|
||||||
uint64_t _ctime = TimeManager->GetCounter();
|
uint64_t _ctime = TimeManager->GetTimeNs();
|
||||||
Tasking::TaskInfo *Ptinfo = &thisProcess->Info;
|
Tasking::TaskInfo *Ptinfo = &thisProcess->Info;
|
||||||
Tasking::TaskInfo *Ttinfo = &thisThread->Info;
|
Tasking::TaskInfo *Ttinfo = &thisThread->Info;
|
||||||
uintptr_t ret;
|
uintptr_t ret;
|
||||||
@ -97,7 +97,7 @@ extern "C" uintptr_t SystemCallsHandler(SyscallsFrame *Frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ret:
|
Ret:
|
||||||
Ptinfo->KernelTime += TimeManager->GetCounter() - _ctime;
|
Ptinfo->KernelTime += TimeManager->GetTimeNs() - _ctime;
|
||||||
Ttinfo->KernelTime += TimeManager->GetCounter() - _ctime;
|
Ttinfo->KernelTime += TimeManager->GetTimeNs() - _ctime;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <time.hpp>
|
|
||||||
|
|
||||||
#include <memory.hpp>
|
|
||||||
#include <acpi.hpp>
|
|
||||||
#include <debug.h>
|
|
||||||
#include <io.h>
|
|
||||||
|
|
||||||
#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()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <time.hpp>
|
|
||||||
|
|
||||||
#include <memory.hpp>
|
|
||||||
#include <acpi.hpp>
|
|
||||||
#include <debug.h>
|
|
||||||
#include <io.h>
|
|
||||||
|
|
||||||
|
|
||||||
#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()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <time.hpp>
|
|
||||||
|
|
||||||
#include <memory.hpp>
|
|
||||||
#include <acpi.hpp>
|
|
||||||
#include <debug.h>
|
|
||||||
#include <io.h>
|
|
||||||
|
|
||||||
#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()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
@ -626,11 +626,11 @@ namespace Tasking
|
|||||||
void WaitForThreadStatus(TCB *tcb, TaskState State);
|
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,
|
PCB *CreateProcess(PCB *Parent,
|
||||||
const char *Name,
|
const char *Name,
|
||||||
|
@ -21,9 +21,24 @@
|
|||||||
#include <types.h>
|
#include <types.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Time
|
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
|
struct Clock
|
||||||
{
|
{
|
||||||
int Year, Month, Day, Hour, Minute, Second;
|
int Year, Month, Day, Hour, Minute, Second;
|
||||||
@ -33,138 +48,148 @@ namespace Time
|
|||||||
Clock ReadClock();
|
Clock ReadClock();
|
||||||
Clock ConvertFromUnix(int Timestamp);
|
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,
|
public:
|
||||||
Picoseconds,
|
const char *Name() const override { return "PIT"; }
|
||||||
Nanoseconds,
|
bool IsAvailable() const override;
|
||||||
Microseconds,
|
bool SupportsNanoseconds() const override { return false; }
|
||||||
Milliseconds,
|
|
||||||
Seconds,
|
bool Sleep(uint64_t Nanoseconds) override;
|
||||||
Minutes,
|
uint64_t GetNanoseconds() override { return 0; }
|
||||||
Hours,
|
|
||||||
Days,
|
ProgrammableIntervalTimer();
|
||||||
Months,
|
~ProgrammableIntervalTimer();
|
||||||
Years
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @deprecated this shouldn't be used */
|
class RealTimeClock : public ITimer
|
||||||
inline uint64_t ConvertUnit(const Units Unit)
|
|
||||||
{
|
{
|
||||||
switch (Unit)
|
public:
|
||||||
{
|
const char *Name() const override { return "RTC"; }
|
||||||
case Femtoseconds:
|
bool IsAvailable() const override;
|
||||||
return 1;
|
bool SupportsNanoseconds() const override { return false; }
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class HighPrecisionEventTimer
|
bool Sleep(uint64_t Nanoseconds) override;
|
||||||
|
uint64_t GetNanoseconds() override { return 0; }
|
||||||
|
|
||||||
|
RealTimeClock();
|
||||||
|
~RealTimeClock();
|
||||||
|
};
|
||||||
|
|
||||||
|
class HighPrecisionEventTimer : public ITimer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
struct HPET
|
struct HPET
|
||||||
{
|
{
|
||||||
uint64_t GeneralCapabilities;
|
uint64_t CapabilitiesID;
|
||||||
uint64_t Reserved0;
|
uint64_t __reserved0;
|
||||||
uint64_t GeneralConfiguration;
|
uint64_t Configuration;
|
||||||
uint64_t Reserved1;
|
uint64_t __reserved1;
|
||||||
uint64_t GeneralIntStatus;
|
uint64_t InterruptStatus;
|
||||||
uint64_t Reserved2;
|
uint64_t __reserved2[25];
|
||||||
uint64_t Reserved3[24];
|
uint64_t MainCounter;
|
||||||
uint64_t MainCounterValue;
|
uint64_t __reserved3;
|
||||||
uint64_t Reserved4;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t clk = 0;
|
uint64_t Period = 0;
|
||||||
HPET *hpet = nullptr;
|
HPET *hpet = nullptr;
|
||||||
uint64_t ClassCreationTime = 0;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool Sleep(size_t Duration, Units Unit);
|
const char *Name() const override { return "HPET"; }
|
||||||
uint64_t GetCounter();
|
bool IsAvailable() const override { return hpet != nullptr; }
|
||||||
uint64_t CalculateTarget(uint64_t Target, Units Unit);
|
bool SupportsNanoseconds() const override { return true; }
|
||||||
uint64_t GetNanosecondsSinceClassCreation();
|
bool Sleep(uint64_t Nanoseconds) override;
|
||||||
|
uint64_t GetNanoseconds() override;
|
||||||
|
|
||||||
HighPrecisionEventTimer(void *hpet);
|
HighPrecisionEventTimer(void *hpet);
|
||||||
~HighPrecisionEventTimer();
|
~HighPrecisionEventTimer();
|
||||||
};
|
};
|
||||||
|
|
||||||
class TimeStampCounter
|
class TimeStampCounter : public ITimer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
uint64_t clk = 0;
|
uint64_t clk = 0;
|
||||||
uint64_t ClassCreationTime = 0;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool Sleep(size_t Duration, Units Unit);
|
const char *Name() const override { return "TSC"; }
|
||||||
uint64_t GetCounter();
|
bool IsAvailable() const override { return clk != 0; }
|
||||||
uint64_t CalculateTarget(uint64_t Target, Units Unit);
|
bool SupportsNanoseconds() const override { return true; }
|
||||||
uint64_t GetNanosecondsSinceClassCreation();
|
bool Sleep(uint64_t Nanoseconds) override;
|
||||||
|
uint64_t GetNanoseconds() override;
|
||||||
|
|
||||||
TimeStampCounter();
|
TimeStampCounter();
|
||||||
~TimeStampCounter();
|
~TimeStampCounter() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
class time
|
class KVMClock : public ITimer
|
||||||
{
|
{
|
||||||
public:
|
private:
|
||||||
enum TimeActiveTimer
|
struct kvm_clock_pairing
|
||||||
{
|
{
|
||||||
NONE = 0b0,
|
int64_t sec;
|
||||||
RTC = 0b1,
|
int64_t nsec;
|
||||||
PIT = 0b10,
|
uint64_t tsc;
|
||||||
HPET = 0b100,
|
uint32_t flags;
|
||||||
ACPI = 0b1000,
|
uint32_t pad[9];
|
||||||
APIC = 0b10000,
|
|
||||||
TSC = 0b100000
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
struct pvclock_vcpu_time_info
|
||||||
int SupportedTimers = 0;
|
{
|
||||||
TimeActiveTimer ActiveTimer = NONE;
|
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;
|
struct ms_hyperv_tsc_page
|
||||||
TimeStampCounter *tsc;
|
{
|
||||||
|
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:
|
public:
|
||||||
int GetSupportedTimers() { return SupportedTimers; }
|
const char *Name() const override { return "KVM"; }
|
||||||
TimeActiveTimer GetActiveTimer() { return ActiveTimer; }
|
bool IsAvailable() const override { return clk != 0; }
|
||||||
bool ChangeActiveTimer(TimeActiveTimer Timer)
|
bool SupportsNanoseconds() const override { return true; }
|
||||||
{
|
bool Sleep(uint64_t Nanoseconds) override;
|
||||||
if (!(SupportedTimers & Timer))
|
uint64_t GetNanoseconds() override;
|
||||||
return false;
|
|
||||||
ActiveTimer = Timer;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sleep(size_t Duration, Units Unit);
|
KVMClock();
|
||||||
uint64_t GetCounter();
|
~KVMClock();
|
||||||
uint64_t CalculateTarget(uint64_t Target, Units Unit);
|
};
|
||||||
uint64_t GetNanosecondsSinceClassCreation();
|
|
||||||
void FindTimers(void *acpi);
|
class Manager
|
||||||
time();
|
{
|
||||||
~time();
|
private:
|
||||||
|
void *acpi = nullptr;
|
||||||
|
std::vector<ITimer *> 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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ struct KernelConfig Config = {
|
|||||||
Video::Display *Display = nullptr;
|
Video::Display *Display = nullptr;
|
||||||
SymbolResolver::Symbols *KernelSymbolTable = nullptr;
|
SymbolResolver::Symbols *KernelSymbolTable = nullptr;
|
||||||
Power::Power *PowerManager = nullptr;
|
Power::Power *PowerManager = nullptr;
|
||||||
Time::time *TimeManager = nullptr;
|
Time::Manager *TimeManager = nullptr;
|
||||||
Tasking::Task *TaskManager = nullptr;
|
Tasking::Task *TaskManager = nullptr;
|
||||||
PCI::Manager *PCIManager = nullptr;
|
PCI::Manager *PCIManager = nullptr;
|
||||||
Driver::Manager *DriverManager = nullptr;
|
Driver::Manager *DriverManager = nullptr;
|
||||||
@ -76,14 +76,14 @@ EXTERNC void _KPrint(const char *Format, va_list Args)
|
|||||||
{
|
{
|
||||||
SmartLock(KernelLock);
|
SmartLock(KernelLock);
|
||||||
|
|
||||||
uint64_t nano = TimeManager ? TimeManager->GetNanosecondsSinceClassCreation() : 0;
|
uint64_t nano = TimeManager ? TimeManager->GetTimeNs() : 0;
|
||||||
|
|
||||||
#if defined(__amd64__)
|
#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__)
|
#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__)
|
#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
|
#endif
|
||||||
|
|
||||||
vprintf(Format, Args);
|
vprintf(Format, Args);
|
||||||
@ -232,8 +232,8 @@ EXTERNC nif cold void Main()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
KPrint("Initializing Timers");
|
KPrint("Initializing Timers");
|
||||||
TimeManager = new Time::time;
|
TimeManager = new Time::Manager(PowerManager->GetACPI());
|
||||||
TimeManager->FindTimers(PowerManager->GetACPI());
|
TimeManager->InitializeTimers();
|
||||||
|
|
||||||
KPrint("Initializing PCI Manager");
|
KPrint("Initializing PCI Manager");
|
||||||
PCIManager = new PCI::Manager;
|
PCIManager = new PCI::Manager;
|
||||||
@ -388,12 +388,6 @@ EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot)
|
|||||||
if (fs)
|
if (fs)
|
||||||
delete fs, fs = nullptr;
|
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
|
// https://wiki.osdev.org/Calling_Global_Constructors
|
||||||
KPrint("Calling destructors");
|
KPrint("Calling destructors");
|
||||||
for (CallPtr *fct = __fini_array_start; fct != __fini_array_end; fct++)
|
for (CallPtr *fct = __fini_array_start; fct != __fini_array_end; fct++)
|
||||||
|
@ -48,7 +48,7 @@ extern bool DebuggerIsAttached;
|
|||||||
extern Video::Display *Display;
|
extern Video::Display *Display;
|
||||||
extern SymbolResolver::Symbols *KernelSymbolTable;
|
extern SymbolResolver::Symbols *KernelSymbolTable;
|
||||||
extern Power::Power *PowerManager;
|
extern Power::Power *PowerManager;
|
||||||
extern Time::time *TimeManager;
|
extern Time::Manager *TimeManager;
|
||||||
extern PCI::Manager *PCIManager;
|
extern PCI::Manager *PCIManager;
|
||||||
extern vfs::Virtual *fs;
|
extern vfs::Virtual *fs;
|
||||||
extern Tasking::Task *TaskManager;
|
extern Tasking::Task *TaskManager;
|
||||||
|
@ -169,7 +169,7 @@ Exit:
|
|||||||
ExitCode, ExitCode < 0 ? -ExitCode : ExitCode);
|
ExitCode, ExitCode < 0 ? -ExitCode : ExitCode);
|
||||||
|
|
||||||
KPrint("Dropping to kernel shell");
|
KPrint("Dropping to kernel shell");
|
||||||
TaskManager->Sleep(1000);
|
TaskManager->Sleep(Time::FromMilliseconds(1000));
|
||||||
TaskManager->CreateThread(thisProcess, Tasking::IP(KShellThread))->Rename("Kernel Shell");
|
TaskManager->CreateThread(thisProcess, Tasking::IP(KShellThread))->Rename("Kernel Shell");
|
||||||
CPU::Halt(true);
|
CPU::Halt(true);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ void cmd_uptime(const char *)
|
|||||||
if (TimeManager)
|
if (TimeManager)
|
||||||
{
|
{
|
||||||
uint64_t Nanoseconds =
|
uint64_t Nanoseconds =
|
||||||
TimeManager->GetNanosecondsSinceClassCreation();
|
TimeManager->GetTimeNs();
|
||||||
uint64_t Seconds = Nanoseconds / 10000000;
|
uint64_t Seconds = Nanoseconds / 10000000;
|
||||||
uint64_t Minutes = Seconds / 60;
|
uint64_t Minutes = Seconds / 60;
|
||||||
uint64_t Hours = Minutes / 60;
|
uint64_t Hours = Minutes / 60;
|
||||||
|
@ -1389,10 +1389,10 @@ static int linux_nanosleep(SysFrm *,
|
|||||||
pReq->tv_nsec, pReq->tv_sec);
|
pReq->tv_nsec, pReq->tv_sec);
|
||||||
|
|
||||||
uint64_t nanoTime = pReq->tv_nsec;
|
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 time = TimeManager->GetTimeNs();
|
||||||
uint64_t sleepTime = TimeManager->CalculateTarget(nanoTime + secTime, Time::Nanoseconds);
|
uint64_t sleepTime = TimeManager->GetTimeNs() + secTime + nanoTime;
|
||||||
|
|
||||||
debug("time=%ld secTime=%ld nanoTime=%ld sleepTime=%ld",
|
debug("time=%ld secTime=%ld nanoTime=%ld sleepTime=%ld",
|
||||||
time, secTime, nanoTime, sleepTime);
|
time, secTime, nanoTime, sleepTime);
|
||||||
@ -1406,7 +1406,7 @@ static int linux_nanosleep(SysFrm *,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pcb->GetContext()->Yield();
|
pcb->GetContext()->Yield();
|
||||||
time = TimeManager->GetCounter();
|
time = TimeManager->GetTimeNs();
|
||||||
}
|
}
|
||||||
debug("time= %ld", time);
|
debug("time= %ld", time);
|
||||||
debug("sleepTime=%ld", sleepTime);
|
debug("sleepTime=%ld", sleepTime);
|
||||||
@ -2582,7 +2582,7 @@ static int linux_sysinfo(SysFrm *, struct sysinfo *info)
|
|||||||
if (pInfo == nullptr)
|
if (pInfo == nullptr)
|
||||||
return -linux_EFAULT;
|
return -linux_EFAULT;
|
||||||
|
|
||||||
uint64_t nano = TimeManager->GetNanosecondsSinceClassCreation();
|
uint64_t nano = TimeManager->GetTimeNs();
|
||||||
if (nano != 0)
|
if (nano != 0)
|
||||||
nano /= 10000000;
|
nano /= 10000000;
|
||||||
|
|
||||||
@ -3185,18 +3185,18 @@ static int linux_clock_gettime(SysFrm *, clockid_t clockid, struct timespec *tp)
|
|||||||
{
|
{
|
||||||
case linux_CLOCK_REALTIME:
|
case linux_CLOCK_REALTIME:
|
||||||
{
|
{
|
||||||
uint64_t time = TimeManager->GetCounter();
|
uint64_t time = TimeManager->GetTimeNs();
|
||||||
pTp->tv_sec = time / Time::ConvertUnit(Time::Seconds);
|
pTp->tv_sec = Time::ToSeconds(time);
|
||||||
pTp->tv_nsec = time / Time::ConvertUnit(Time::Nanoseconds);
|
pTp->tv_nsec = time;
|
||||||
debug("time=%ld sec=%ld nsec=%ld",
|
debug("time=%ld sec=%ld nsec=%ld",
|
||||||
time, pTp->tv_sec, pTp->tv_nsec);
|
time, pTp->tv_sec, pTp->tv_nsec);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case linux_CLOCK_MONOTONIC:
|
case linux_CLOCK_MONOTONIC:
|
||||||
{
|
{
|
||||||
uint64_t time = TimeManager->GetCounter();
|
uint64_t time = TimeManager->GetTimeNs();
|
||||||
pTp->tv_sec = time / Time::ConvertUnit(Time::Seconds);
|
pTp->tv_sec = Time::ToSeconds(time);
|
||||||
pTp->tv_nsec = time / Time::ConvertUnit(Time::Nanoseconds);
|
pTp->tv_nsec = time;
|
||||||
debug("time=%ld sec=%ld nsec=%ld",
|
debug("time=%ld sec=%ld nsec=%ld",
|
||||||
time, pTp->tv_sec, pTp->tv_nsec);
|
time, pTp->tv_sec, pTp->tv_nsec);
|
||||||
break;
|
break;
|
||||||
@ -3244,9 +3244,8 @@ static int linux_clock_nanosleep(SysFrm *, clockid_t clockid, int flags,
|
|||||||
case linux_CLOCK_REALTIME:
|
case linux_CLOCK_REALTIME:
|
||||||
case linux_CLOCK_MONOTONIC:
|
case linux_CLOCK_MONOTONIC:
|
||||||
{
|
{
|
||||||
uint64_t time = TimeManager->GetCounter();
|
uint64_t time = TimeManager->GetTimeNs();
|
||||||
uint64_t rqTime = pRequest->tv_sec * Time::ConvertUnit(Time::Seconds) +
|
uint64_t rqTime = Time::FromSeconds(pRequest->tv_sec) + pRequest->tv_nsec;
|
||||||
pRequest->tv_nsec * Time::ConvertUnit(Time::Nanoseconds);
|
|
||||||
|
|
||||||
debug("Sleeping for %ld", rqTime - time);
|
debug("Sleeping for %ld", rqTime - time);
|
||||||
if (rqTime > time)
|
if (rqTime > time)
|
||||||
|
100
Kernel/subsystem/time/hpet.cpp
Normal file
100
Kernel/subsystem/time/hpet.cpp
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.hpp>
|
||||||
|
|
||||||
|
#include <memory.hpp>
|
||||||
|
#include <acpi.hpp>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
#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<HPET *>(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
|
||||||
|
}
|
||||||
|
}
|
71
Kernel/subsystem/time/kvm_clock.cpp
Normal file
71
Kernel/subsystem/time/kvm_clock.cpp
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.hpp>
|
||||||
|
|
||||||
|
#include <memory.hpp>
|
||||||
|
#include <acpi.hpp>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
#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()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
107
Kernel/subsystem/time/manager.cpp
Normal file
107
Kernel/subsystem/time/manager.cpp
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.hpp>
|
||||||
|
|
||||||
|
#include <memory.hpp>
|
||||||
|
#include <acpi.hpp>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
#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) {}
|
||||||
|
}
|
105
Kernel/subsystem/time/tsc.cpp
Normal file
105
Kernel/subsystem/time/tsc.cpp
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.hpp>
|
||||||
|
|
||||||
|
#include <memory.hpp>
|
||||||
|
#include <acpi.hpp>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
#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 */
|
||||||
|
}
|
||||||
|
}
|
@ -251,7 +251,7 @@ namespace Tasking
|
|||||||
this->AllocatedMemory += sizeof(Memory::ProgramBreak);
|
this->AllocatedMemory += sizeof(Memory::ProgramBreak);
|
||||||
this->AllocatedMemory += sizeof(SymbolResolver::Symbols);
|
this->AllocatedMemory += sizeof(SymbolResolver::Symbols);
|
||||||
|
|
||||||
this->Info.SpawnTime = TimeManager->GetCounter();
|
this->Info.SpawnTime = TimeManager->GetTimeNs();
|
||||||
|
|
||||||
if (Parent)
|
if (Parent)
|
||||||
Parent->Children.push_back(this);
|
Parent->Children.push_back(this);
|
||||||
|
@ -290,7 +290,7 @@ namespace Tasking::Scheduler
|
|||||||
hot nsa void Custom::UpdateUsage(TaskInfo *Info, TaskExecutionMode Mode, int Core)
|
hot nsa void Custom::UpdateUsage(TaskInfo *Info, TaskExecutionMode Mode, int Core)
|
||||||
{
|
{
|
||||||
UNUSED(Core);
|
UNUSED(Core);
|
||||||
uint64_t CurrentTime = TimeManager->GetCounter();
|
uint64_t CurrentTime = TimeManager->GetTimeNs();
|
||||||
uint64_t TimePassed = Info->LastUpdateTime - CurrentTime;
|
uint64_t TimePassed = Info->LastUpdateTime - CurrentTime;
|
||||||
Info->LastUpdateTime = CurrentTime;
|
Info->LastUpdateTime = CurrentTime;
|
||||||
|
|
||||||
@ -529,7 +529,7 @@ namespace Tasking::Scheduler
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Check if the thread is ready to wake up. */
|
/* 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)
|
if (pState == TaskState::Sleeping)
|
||||||
process->State.store(TaskState::Ready);
|
process->State.store(TaskState::Ready);
|
||||||
@ -541,7 +541,7 @@ namespace Tasking::Scheduler
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
wut_schedbg("Thread \"%s\"(%d) is not ready to wake up. (SleepUntil: %d, Counter: %d)",
|
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;
|
return;
|
||||||
}
|
}
|
||||||
bool ProcessNotChanged = false;
|
bool ProcessNotChanged = false;
|
||||||
uint64_t SchedTmpTicks = TimeManager->GetCounter();
|
uint64_t SchedTmpTicks = TimeManager->GetTimeNs();
|
||||||
this->LastTaskTicks.store(size_t(SchedTmpTicks - this->SchedulerTicks.load()));
|
this->LastTaskTicks.store(size_t(SchedTmpTicks - this->SchedulerTicks.load()));
|
||||||
CPUData *CurrentCPU = GetCurrentCPU();
|
CPUData *CurrentCPU = GetCurrentCPU();
|
||||||
this->LastCore.store(CurrentCPU->ID);
|
this->LastCore.store(CurrentCPU->ID);
|
||||||
@ -621,7 +621,7 @@ namespace Tasking::Scheduler
|
|||||||
CurrentCPU->CurrentProcess->State.store(TaskState::Running);
|
CurrentCPU->CurrentProcess->State.store(TaskState::Running);
|
||||||
CurrentCPU->CurrentThread->State.store(TaskState::Running);
|
CurrentCPU->CurrentThread->State.store(TaskState::Running);
|
||||||
*Frame = CurrentCPU->CurrentThread->Registers;
|
*Frame = CurrentCPU->CurrentThread->Registers;
|
||||||
this->SchedulerTicks.store(size_t(TimeManager->GetCounter() - SchedTmpTicks));
|
this->SchedulerTicks.store(size_t(TimeManager->GetTimeNs() - SchedTmpTicks));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -696,8 +696,8 @@ namespace Tasking::Scheduler
|
|||||||
CurrentCPU->CurrentProcess->Signals.HandleSignal(Frame, CurrentCPU->CurrentThread.load());
|
CurrentCPU->CurrentProcess->Signals.HandleSignal(Frame, CurrentCPU->CurrentThread.load());
|
||||||
|
|
||||||
if (!ProcessNotChanged)
|
if (!ProcessNotChanged)
|
||||||
(&CurrentCPU->CurrentProcess->Info)->LastUpdateTime = TimeManager->GetCounter();
|
(&CurrentCPU->CurrentProcess->Info)->LastUpdateTime = TimeManager->GetTimeNs();
|
||||||
(&CurrentCPU->CurrentThread->Info)->LastUpdateTime = TimeManager->GetCounter();
|
(&CurrentCPU->CurrentThread->Info)->LastUpdateTime = TimeManager->GetTimeNs();
|
||||||
this->OneShot(CurrentCPU->CurrentThread->Info.Priority);
|
this->OneShot(CurrentCPU->CurrentThread->Info.Priority);
|
||||||
|
|
||||||
if (CurrentCPU->CurrentThread->Security.IsDebugEnabled &&
|
if (CurrentCPU->CurrentThread->Security.IsDebugEnabled &&
|
||||||
@ -720,7 +720,7 @@ namespace Tasking::Scheduler
|
|||||||
#endif
|
#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)
|
hot nsa nif void Custom::OnInterruptReceived(CPU::SchedulerFrame *Frame)
|
||||||
@ -754,7 +754,7 @@ namespace Tasking::Scheduler
|
|||||||
}
|
}
|
||||||
|
|
||||||
debug("Waiting for processes to terminate");
|
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)
|
while (this->GetProcessList().size() > 0)
|
||||||
{
|
{
|
||||||
trace("Waiting for %d processes to terminate", this->GetProcessList().size());
|
trace("Waiting for %d processes to terminate", this->GetProcessList().size());
|
||||||
@ -780,7 +780,7 @@ namespace Tasking::Scheduler
|
|||||||
ctx->GetCurrentProcess()->Name,
|
ctx->GetCurrentProcess()->Name,
|
||||||
ctx->GetCurrentProcess()->ID);
|
ctx->GetCurrentProcess()->ID);
|
||||||
|
|
||||||
if (TimeManager->GetCounter() > timeout)
|
if (TimeManager->GetTimeNs() > timeout)
|
||||||
{
|
{
|
||||||
error("Timeout waiting for processes to terminate");
|
error("Timeout waiting for processes to terminate");
|
||||||
break;
|
break;
|
||||||
|
@ -167,7 +167,7 @@ namespace Tasking
|
|||||||
this->Yield();
|
this->Yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Task::Sleep(uint64_t Milliseconds, bool NoSwitch)
|
void Task::Sleep(uint64_t Nanoseconds, bool NoSwitch)
|
||||||
{
|
{
|
||||||
TCB *thread = this->GetCurrentThread();
|
TCB *thread = this->GetCurrentThread();
|
||||||
PCB *process = thread->Parent;
|
PCB *process = thread->Parent;
|
||||||
@ -179,13 +179,11 @@ namespace Tasking
|
|||||||
if (process->Threads.size() == 1)
|
if (process->Threads.size() == 1)
|
||||||
process->SetState(TaskState::Sleeping);
|
process->SetState(TaskState::Sleeping);
|
||||||
|
|
||||||
thread->Info.SleepUntil =
|
thread->Info.SleepUntil = TimeManager->GetTimeNs() + Nanoseconds;
|
||||||
TimeManager->CalculateTarget(Milliseconds,
|
|
||||||
Time::Units::Milliseconds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// #ifdef DEBUG
|
// #ifdef DEBUG
|
||||||
// uint64_t TicksNow = TimeManager->GetCounter();
|
// uint64_t TicksNow = TimeManager->GetTimeNs();
|
||||||
// #endif
|
// #endif
|
||||||
// debug("Thread \"%s\"(%d) is going to sleep until %llu, current %llu, diff %llu",
|
// debug("Thread \"%s\"(%d) is going to sleep until %llu, current %llu, diff %llu",
|
||||||
// thread->Name, thread->ID, thread->Info.SleepUntil,
|
// thread->Name, thread->ID, thread->Info.SleepUntil,
|
||||||
|
@ -650,7 +650,7 @@ namespace Tasking
|
|||||||
this->AllocatedMemory += strlen(this->Parent->Name) + 1;
|
this->AllocatedMemory += strlen(this->Parent->Name) + 1;
|
||||||
this->AllocatedMemory += sizeof(Memory::StackGuard);
|
this->AllocatedMemory += sizeof(Memory::StackGuard);
|
||||||
|
|
||||||
this->Info.SpawnTime = TimeManager->GetCounter();
|
this->Info.SpawnTime = TimeManager->GetTimeNs();
|
||||||
this->Parent->Threads.push_back(this);
|
this->Parent->Threads.push_back(this);
|
||||||
|
|
||||||
if (this->Parent->Threads.size() == 1 &&
|
if (this->Parent->Threads.size() == 1 &&
|
||||||
|
@ -70,23 +70,23 @@ void readdir_sanity_tests()
|
|||||||
|
|
||||||
KPrint("TEST /");
|
KPrint("TEST /");
|
||||||
TestReadDirectory(t0);
|
TestReadDirectory(t0);
|
||||||
TaskManager->Sleep(2000);
|
TaskManager->Sleep(Time::FromMilliseconds(2000));
|
||||||
|
|
||||||
KPrint("TEST /dev");
|
KPrint("TEST /dev");
|
||||||
TestReadDirectory(t1);
|
TestReadDirectory(t1);
|
||||||
TaskManager->Sleep(2000);
|
TaskManager->Sleep(Time::FromMilliseconds(2000));
|
||||||
|
|
||||||
KPrint("TEST /home");
|
KPrint("TEST /home");
|
||||||
TestReadDirectory(t2);
|
TestReadDirectory(t2);
|
||||||
TaskManager->Sleep(2000);
|
TaskManager->Sleep(Time::FromMilliseconds(2000));
|
||||||
|
|
||||||
KPrint("TEST /var");
|
KPrint("TEST /var");
|
||||||
TestReadDirectory(t3);
|
TestReadDirectory(t3);
|
||||||
TaskManager->Sleep(2000);
|
TaskManager->Sleep(Time::FromMilliseconds(2000));
|
||||||
|
|
||||||
KPrint("TEST /tmp");
|
KPrint("TEST /tmp");
|
||||||
TestReadDirectory(t4);
|
TestReadDirectory(t4);
|
||||||
TaskManager->Sleep(2000);
|
TaskManager->Sleep(Time::FromMilliseconds(2000));
|
||||||
|
|
||||||
CPU::Stop();
|
CPU::Stop();
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ void TaskHeartbeat()
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
debug("Task Heartbeat");
|
debug("Task Heartbeat");
|
||||||
TaskManager->Sleep(5000);
|
TaskManager->Sleep(Time::FromMilliseconds(5000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ void TaskMgr_Dummy100Usage()
|
|||||||
void TaskMgr_Dummy0Usage()
|
void TaskMgr_Dummy0Usage()
|
||||||
{
|
{
|
||||||
while (1)
|
while (1)
|
||||||
TaskManager->Sleep(1000000);
|
TaskManager->Sleep(Time::FromMilliseconds(1000000));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t GetUsage(uint64_t OldSystemTime, Tasking::TaskInfo *Info)
|
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 */
|
/* https://github.com/reactos/reactos/blob/560671a784c1e0e0aa7590df5e0598c1e2f41f5a/base/applications/taskmgr/perfdata.c#L347 */
|
||||||
if (Info->OldKernelTime || Info->OldUserTime)
|
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 CurrentTime = Info->KernelTime + Info->UserTime;
|
||||||
uint64_t OldTime = Info->OldKernelTime + Info->OldUserTime;
|
uint64_t OldTime = Info->OldKernelTime + Info->OldUserTime;
|
||||||
uint64_t CpuUsage = (CurrentTime - OldTime) / SystemTime;
|
uint64_t CpuUsage = (CurrentTime - OldTime) / SystemTime;
|
||||||
@ -168,7 +168,7 @@ void TaskMgr()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OldSystemTime = TimeManager->GetCounter();
|
OldSystemTime = TimeManager->GetTimeNs();
|
||||||
#if defined(__amd64__)
|
#if defined(__amd64__)
|
||||||
register uintptr_t CurrentStackAddress asm("rsp");
|
register uintptr_t CurrentStackAddress asm("rsp");
|
||||||
printf("Sanity: %d, Stack: %#lx", sanity++, CurrentStackAddress);
|
printf("Sanity: %d, Stack: %#lx", sanity++, CurrentStackAddress);
|
||||||
@ -185,7 +185,7 @@ void TaskMgr()
|
|||||||
if (!Config.Quiet)
|
if (!Config.Quiet)
|
||||||
Display->UpdateBuffer();
|
Display->UpdateBuffer();
|
||||||
|
|
||||||
TaskManager->Sleep(100);
|
TaskManager->Sleep(Time::FromMilliseconds(100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
Makefile
2
Makefile
@ -14,6 +14,7 @@ QEMUFLAGS := -display gtk
|
|||||||
|
|
||||||
ifeq ($(OSARCH), amd64)
|
ifeq ($(OSARCH), amd64)
|
||||||
QEMUFLAGS += -device vmware-svga -M q35 \
|
QEMUFLAGS += -device vmware-svga -M q35 \
|
||||||
|
-cpu max \
|
||||||
-usb \
|
-usb \
|
||||||
-device qemu-xhci,id=xhci \
|
-device qemu-xhci,id=xhci \
|
||||||
-net user \
|
-net user \
|
||||||
@ -40,6 +41,7 @@ QEMUFLAGS += -device vmware-svga -M q35 \
|
|||||||
-acpitable file=tools/acpi/SSDT1.dat
|
-acpitable file=tools/acpi/SSDT1.dat
|
||||||
else ifeq ($(OSARCH), i386)
|
else ifeq ($(OSARCH), i386)
|
||||||
QEMUFLAGS += -M q35 \
|
QEMUFLAGS += -M q35 \
|
||||||
|
-cpu max \
|
||||||
-usb \
|
-usb \
|
||||||
-device qemu-xhci,id=xhci \
|
-device qemu-xhci,id=xhci \
|
||||||
-device usb-mouse,bus=xhci.0,pcap=mousex.pcap \
|
-device usb-mouse,bus=xhci.0,pcap=mousex.pcap \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user