diff --git a/Kernel/Arch/aarch64/Dummy.cpp b/Kernel/Arch/aarch64/Dummy.cpp index 0fa4c937d5..ddd4353452 100644 --- a/Kernel/Arch/aarch64/Dummy.cpp +++ b/Kernel/Arch/aarch64/Dummy.cpp @@ -15,12 +15,19 @@ #include #include #include +#include #include #include // Scheduler 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; RecursiveSpinlock g_scheduler_lock { LockRank::None }; diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index d16a9a33d0..ac8d6b3a3d 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -503,6 +503,8 @@ else() KSyms.cpp MiniStdLib.cpp StdLib.cpp + Time/TimeManagement.cpp + TimerQueue.cpp UBSanitizer.cpp UserOrKernelBuffer.cpp diff --git a/Kernel/Time/TimeManagement.cpp b/Kernel/Time/TimeManagement.cpp index b11f1e7c0f..6bed75fc93 100644 --- a/Kernel/Time/TimeManagement.cpp +++ b/Kernel/Time/TimeManagement.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Liav A. + * Copyright (c) 2022, Timon Kruiper * * SPDX-License-Identifier: BSD-2-Clause */ @@ -7,6 +8,7 @@ #include #include #include + #if ARCH(I386) || ARCH(X86_64) # include # include @@ -15,7 +17,12 @@ # include # include # include +#elif ARCH(AARCH64) +# include +#else +# error Unknown architecture #endif + #include #include #include @@ -118,12 +125,19 @@ Time TimeManagement::monotonic_time(TimePrecision precision) const ticks = m_ticks_this_second; if (do_query) { +#if ARCH(I386) || ARCH(X86_64) // 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 // seconds and ticks became invalid, producing an incorrect time. // Be sure to not modify m_seconds_since_boot and m_ticks_this_second // because this may only be modified by the interrupt handler HPET::the().update_time(seconds, ticks, true); +#elif ARCH(AARCH64) + // FIXME: Get rid of these horrible casts + const_cast(static_cast(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)); @@ -158,6 +172,10 @@ u64 TimeManagement::uptime_ms() const 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 (cpu == 0) { VERIFY(!s_the.is_initialized()); @@ -180,12 +198,19 @@ UNMAP_AFTER_INIT void TimeManagement::initialize([[maybe_unused]] u32 cpu) 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(); if (possible_arch_specific_current_time_function) s_scheduler_current_time = possible_arch_specific_current_time_function; else s_scheduler_current_time = current_time_monotonic; -#endif } void TimeManagement::set_system_timer(HardwareTimerBase& timer) @@ -204,7 +229,13 @@ time_t TimeManagement::ticks_per_second() const time_t TimeManagement::boot_time() { +#if ARCH(I386) || ARCH(X86_64) return RTC::boot_time(); +#elif ARCH(AARCH64) + TODO_AARCH64(); +#else +# error Unknown architecture +#endif } UNMAP_AFTER_INIT TimeManagement::TimeManagement() @@ -231,6 +262,10 @@ UNMAP_AFTER_INIT TimeManagement::TimeManagement() } else if (!probe_and_set_x86_legacy_hardware_timers()) { VERIFY_NOT_REACHED(); } +#elif ARCH(AARCH64) + probe_and_set_aarch64_hardware_timers(); +#else +# error Unknown architecture #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(); return true; } -#endif void TimeManagement::update_time(RegisterState const&) { @@ -403,6 +437,38 @@ void TimeManagement::increment_time_since_boot_hpet() 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(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() { diff --git a/Kernel/Time/TimeManagement.h b/Kernel/Time/TimeManagement.h index f5e20d0f66..c722f6c8c1 100644 --- a/Kernel/Time/TimeManagement.h +++ b/Kernel/Time/TimeManagement.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -54,9 +55,7 @@ public: bool is_system_timer(HardwareTimerBase const&) const; - static void update_time(RegisterState const&); static void update_time_hpet(RegisterState const&); - void increment_time_since_boot_hpet(); void increment_time_since_boot(); static bool is_hpet_periodic_mode_allowed(); @@ -85,6 +84,12 @@ private: #if ARCH(I386) || ARCH(X86_64) bool probe_and_set_x86_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 Vector scan_and_initialize_periodic_timers(); Vector scan_for_non_periodic_timers(); @@ -95,6 +100,7 @@ private: static u64 scheduling_current_time(bool); // Variables between m_update1 and m_update2 are synchronized + // FIXME: Replace m_update1 and m_update2 with a SpinlockLocker Atomic m_update1 { 0 }; u32 m_ticks_this_second { 0 }; u64 m_seconds_since_boot { 0 };