mirror of
https://github.com/RGBCube/serenity
synced 2025-05-18 15:15:08 +00:00
Kernel: Implement TimeManagement for aarch64
This sets up the RPi::Timer to trigger an interurpt every 4ms using one of the comparators. The actual time is calculated by looking at the main counter of the RPi::Timer using the Timer::update_time function. A stub for Scheduler::timer_tick is also added, since the TimeManagement code now calls the function.
This commit is contained in:
parent
83b95c135e
commit
01a14ac7af
4 changed files with 85 additions and 4 deletions
|
@ -15,12 +15,19 @@
|
||||||
#include <Kernel/PhysicalAddress.h>
|
#include <Kernel/PhysicalAddress.h>
|
||||||
#include <Kernel/Process.h>
|
#include <Kernel/Process.h>
|
||||||
#include <Kernel/Random.h>
|
#include <Kernel/Random.h>
|
||||||
|
#include <Kernel/Scheduler.h>
|
||||||
#include <Kernel/Sections.h>
|
#include <Kernel/Sections.h>
|
||||||
#include <Kernel/UserOrKernelBuffer.h>
|
#include <Kernel/UserOrKernelBuffer.h>
|
||||||
|
|
||||||
// Scheduler
|
// Scheduler
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
void Scheduler::timer_tick(RegisterState const&) {
|
||||||
|
// NOTE: This function currently will be called by the TimeManagement code,
|
||||||
|
// so there is no TODO_AARCH64. Instead there will be a linker error when
|
||||||
|
// the Scheduler code is compiled for aarch64.
|
||||||
|
};
|
||||||
|
|
||||||
READONLY_AFTER_INIT Thread* g_finalizer;
|
READONLY_AFTER_INIT Thread* g_finalizer;
|
||||||
RecursiveSpinlock g_scheduler_lock { LockRank::None };
|
RecursiveSpinlock g_scheduler_lock { LockRank::None };
|
||||||
|
|
||||||
|
|
|
@ -503,6 +503,8 @@ else()
|
||||||
KSyms.cpp
|
KSyms.cpp
|
||||||
MiniStdLib.cpp
|
MiniStdLib.cpp
|
||||||
StdLib.cpp
|
StdLib.cpp
|
||||||
|
Time/TimeManagement.cpp
|
||||||
|
TimerQueue.cpp
|
||||||
UBSanitizer.cpp
|
UBSanitizer.cpp
|
||||||
UserOrKernelBuffer.cpp
|
UserOrKernelBuffer.cpp
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
|
* Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
|
||||||
|
* Copyright (c) 2022, Timon Kruiper <timonkruiper@gmail.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -7,6 +8,7 @@
|
||||||
#include <AK/Singleton.h>
|
#include <AK/Singleton.h>
|
||||||
#include <AK/StdLibExtras.h>
|
#include <AK/StdLibExtras.h>
|
||||||
#include <AK/Time.h>
|
#include <AK/Time.h>
|
||||||
|
|
||||||
#if ARCH(I386) || ARCH(X86_64)
|
#if ARCH(I386) || ARCH(X86_64)
|
||||||
# include <Kernel/Arch/x86/Time/APICTimer.h>
|
# include <Kernel/Arch/x86/Time/APICTimer.h>
|
||||||
# include <Kernel/Arch/x86/Time/HPET.h>
|
# include <Kernel/Arch/x86/Time/HPET.h>
|
||||||
|
@ -15,7 +17,12 @@
|
||||||
# include <Kernel/Arch/x86/Time/RTC.h>
|
# include <Kernel/Arch/x86/Time/RTC.h>
|
||||||
# include <Kernel/Arch/x86/common/Interrupts/APIC.h>
|
# include <Kernel/Arch/x86/common/Interrupts/APIC.h>
|
||||||
# include <Kernel/Arch/x86/common/RTC.h>
|
# include <Kernel/Arch/x86/common/RTC.h>
|
||||||
|
#elif ARCH(AARCH64)
|
||||||
|
# include <Kernel/Arch/aarch64/RPi/Timer.h>
|
||||||
|
#else
|
||||||
|
# error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <Kernel/Arch/CurrentTime.h>
|
#include <Kernel/Arch/CurrentTime.h>
|
||||||
#include <Kernel/CommandLine.h>
|
#include <Kernel/CommandLine.h>
|
||||||
#include <Kernel/Firmware/ACPI/Parser.h>
|
#include <Kernel/Firmware/ACPI/Parser.h>
|
||||||
|
@ -118,12 +125,19 @@ Time TimeManagement::monotonic_time(TimePrecision precision) const
|
||||||
ticks = m_ticks_this_second;
|
ticks = m_ticks_this_second;
|
||||||
|
|
||||||
if (do_query) {
|
if (do_query) {
|
||||||
|
#if ARCH(I386) || ARCH(X86_64)
|
||||||
// We may have to do this over again if the timer interrupt fires
|
// We may have to do this over again if the timer interrupt fires
|
||||||
// while we're trying to query the information. In that case, our
|
// while we're trying to query the information. In that case, our
|
||||||
// seconds and ticks became invalid, producing an incorrect time.
|
// seconds and ticks became invalid, producing an incorrect time.
|
||||||
// Be sure to not modify m_seconds_since_boot and m_ticks_this_second
|
// Be sure to not modify m_seconds_since_boot and m_ticks_this_second
|
||||||
// because this may only be modified by the interrupt handler
|
// because this may only be modified by the interrupt handler
|
||||||
HPET::the().update_time(seconds, ticks, true);
|
HPET::the().update_time(seconds, ticks, true);
|
||||||
|
#elif ARCH(AARCH64)
|
||||||
|
// FIXME: Get rid of these horrible casts
|
||||||
|
const_cast<RPi::Timer*>(static_cast<RPi::Timer const*>(m_system_timer.ptr()))->update_time(seconds, ticks, true);
|
||||||
|
#else
|
||||||
|
# error Unknown architecture
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} while (update_iteration != m_update2.load(AK::MemoryOrder::memory_order_acquire));
|
} while (update_iteration != m_update2.load(AK::MemoryOrder::memory_order_acquire));
|
||||||
|
|
||||||
|
@ -158,6 +172,10 @@ u64 TimeManagement::uptime_ms() const
|
||||||
|
|
||||||
UNMAP_AFTER_INIT void TimeManagement::initialize([[maybe_unused]] u32 cpu)
|
UNMAP_AFTER_INIT void TimeManagement::initialize([[maybe_unused]] u32 cpu)
|
||||||
{
|
{
|
||||||
|
// Note: We must disable interrupts, because the timers interrupt might fire before
|
||||||
|
// the TimeManagement class is completely initialized.
|
||||||
|
InterruptDisabler disabler;
|
||||||
|
|
||||||
#if ARCH(I386) || ARCH(X86_64)
|
#if ARCH(I386) || ARCH(X86_64)
|
||||||
if (cpu == 0) {
|
if (cpu == 0) {
|
||||||
VERIFY(!s_the.is_initialized());
|
VERIFY(!s_the.is_initialized());
|
||||||
|
@ -180,12 +198,19 @@ UNMAP_AFTER_INIT void TimeManagement::initialize([[maybe_unused]] u32 cpu)
|
||||||
apic_timer->enable_local_timer();
|
apic_timer->enable_local_timer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#elif ARCH(AARCH64)
|
||||||
|
if (cpu == 0) {
|
||||||
|
VERIFY(!s_the.is_initialized());
|
||||||
|
s_the.ensure_instance();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# error Unknown architecture
|
||||||
|
#endif
|
||||||
auto* possible_arch_specific_current_time_function = optional_current_time();
|
auto* possible_arch_specific_current_time_function = optional_current_time();
|
||||||
if (possible_arch_specific_current_time_function)
|
if (possible_arch_specific_current_time_function)
|
||||||
s_scheduler_current_time = possible_arch_specific_current_time_function;
|
s_scheduler_current_time = possible_arch_specific_current_time_function;
|
||||||
else
|
else
|
||||||
s_scheduler_current_time = current_time_monotonic;
|
s_scheduler_current_time = current_time_monotonic;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeManagement::set_system_timer(HardwareTimerBase& timer)
|
void TimeManagement::set_system_timer(HardwareTimerBase& timer)
|
||||||
|
@ -204,7 +229,13 @@ time_t TimeManagement::ticks_per_second() const
|
||||||
|
|
||||||
time_t TimeManagement::boot_time()
|
time_t TimeManagement::boot_time()
|
||||||
{
|
{
|
||||||
|
#if ARCH(I386) || ARCH(X86_64)
|
||||||
return RTC::boot_time();
|
return RTC::boot_time();
|
||||||
|
#elif ARCH(AARCH64)
|
||||||
|
TODO_AARCH64();
|
||||||
|
#else
|
||||||
|
# error Unknown architecture
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
UNMAP_AFTER_INIT TimeManagement::TimeManagement()
|
UNMAP_AFTER_INIT TimeManagement::TimeManagement()
|
||||||
|
@ -231,6 +262,10 @@ UNMAP_AFTER_INIT TimeManagement::TimeManagement()
|
||||||
} else if (!probe_and_set_x86_legacy_hardware_timers()) {
|
} else if (!probe_and_set_x86_legacy_hardware_timers()) {
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
#elif ARCH(AARCH64)
|
||||||
|
probe_and_set_aarch64_hardware_timers();
|
||||||
|
#else
|
||||||
|
# error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,7 +407,6 @@ UNMAP_AFTER_INIT bool TimeManagement::probe_and_set_x86_legacy_hardware_timers()
|
||||||
m_time_ticks_per_second = m_time_keeper_timer->ticks_per_second();
|
m_time_ticks_per_second = m_time_keeper_timer->ticks_per_second();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void TimeManagement::update_time(RegisterState const&)
|
void TimeManagement::update_time(RegisterState const&)
|
||||||
{
|
{
|
||||||
|
@ -403,6 +437,38 @@ void TimeManagement::increment_time_since_boot_hpet()
|
||||||
|
|
||||||
update_time_page();
|
update_time_page();
|
||||||
}
|
}
|
||||||
|
#elif ARCH(AARCH64)
|
||||||
|
UNMAP_AFTER_INIT bool TimeManagement::probe_and_set_aarch64_hardware_timers()
|
||||||
|
{
|
||||||
|
m_hardware_timers.append(RPi::Timer::initialize());
|
||||||
|
m_system_timer = m_hardware_timers[0];
|
||||||
|
m_time_ticks_per_second = m_system_timer->frequency();
|
||||||
|
|
||||||
|
m_system_timer->set_callback([this](RegisterState const& regs) {
|
||||||
|
auto seconds_since_boot = m_seconds_since_boot;
|
||||||
|
auto ticks_this_second = m_ticks_this_second;
|
||||||
|
auto delta_ns = static_cast<RPi::Timer*>(m_system_timer.ptr())->update_time(seconds_since_boot, ticks_this_second, false);
|
||||||
|
|
||||||
|
u32 update_iteration = m_update2.fetch_add(1, AK::MemoryOrder::memory_order_acquire);
|
||||||
|
m_seconds_since_boot = seconds_since_boot;
|
||||||
|
m_ticks_this_second = ticks_this_second;
|
||||||
|
|
||||||
|
timespec_add(m_epoch_time, { (time_t)(delta_ns / 1000000000), (long)(delta_ns % 1000000000) }, m_epoch_time);
|
||||||
|
|
||||||
|
m_update1.store(update_iteration + 1, AK::MemoryOrder::memory_order_release);
|
||||||
|
|
||||||
|
update_time_page();
|
||||||
|
|
||||||
|
system_timer_tick(regs);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_time_keeper_timer = m_system_timer;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# error Unknown architecture
|
||||||
|
#endif
|
||||||
|
|
||||||
void TimeManagement::increment_time_since_boot()
|
void TimeManagement::increment_time_since_boot()
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <Kernel/API/TimePage.h>
|
#include <Kernel/API/TimePage.h>
|
||||||
#include <Kernel/Arch/RegisterState.h>
|
#include <Kernel/Arch/RegisterState.h>
|
||||||
|
#include <Kernel/Forward.h>
|
||||||
#include <Kernel/Library/LockRefPtr.h>
|
#include <Kernel/Library/LockRefPtr.h>
|
||||||
#include <Kernel/Library/NonnullLockRefPtrVector.h>
|
#include <Kernel/Library/NonnullLockRefPtrVector.h>
|
||||||
#include <Kernel/UnixTypes.h>
|
#include <Kernel/UnixTypes.h>
|
||||||
|
@ -54,9 +55,7 @@ public:
|
||||||
|
|
||||||
bool is_system_timer(HardwareTimerBase const&) const;
|
bool is_system_timer(HardwareTimerBase const&) const;
|
||||||
|
|
||||||
static void update_time(RegisterState const&);
|
|
||||||
static void update_time_hpet(RegisterState const&);
|
static void update_time_hpet(RegisterState const&);
|
||||||
void increment_time_since_boot_hpet();
|
|
||||||
void increment_time_since_boot();
|
void increment_time_since_boot();
|
||||||
|
|
||||||
static bool is_hpet_periodic_mode_allowed();
|
static bool is_hpet_periodic_mode_allowed();
|
||||||
|
@ -85,6 +84,12 @@ private:
|
||||||
#if ARCH(I386) || ARCH(X86_64)
|
#if ARCH(I386) || ARCH(X86_64)
|
||||||
bool probe_and_set_x86_legacy_hardware_timers();
|
bool probe_and_set_x86_legacy_hardware_timers();
|
||||||
bool probe_and_set_x86_non_legacy_hardware_timers();
|
bool probe_and_set_x86_non_legacy_hardware_timers();
|
||||||
|
void increment_time_since_boot_hpet();
|
||||||
|
static void update_time(RegisterState const&);
|
||||||
|
#elif ARCH(AARCH64)
|
||||||
|
bool probe_and_set_aarch64_hardware_timers();
|
||||||
|
#else
|
||||||
|
# error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
Vector<HardwareTimerBase*> scan_and_initialize_periodic_timers();
|
Vector<HardwareTimerBase*> scan_and_initialize_periodic_timers();
|
||||||
Vector<HardwareTimerBase*> scan_for_non_periodic_timers();
|
Vector<HardwareTimerBase*> scan_for_non_periodic_timers();
|
||||||
|
@ -95,6 +100,7 @@ private:
|
||||||
static u64 scheduling_current_time(bool);
|
static u64 scheduling_current_time(bool);
|
||||||
|
|
||||||
// Variables between m_update1 and m_update2 are synchronized
|
// Variables between m_update1 and m_update2 are synchronized
|
||||||
|
// FIXME: Replace m_update1 and m_update2 with a SpinlockLocker
|
||||||
Atomic<u32> m_update1 { 0 };
|
Atomic<u32> m_update1 { 0 };
|
||||||
u32 m_ticks_this_second { 0 };
|
u32 m_ticks_this_second { 0 };
|
||||||
u64 m_seconds_since_boot { 0 };
|
u64 m_seconds_since_boot { 0 };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue