فهرست منبع

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.
Timon Kruiper 2 سال پیش
والد
کامیت
01a14ac7af
4فایلهای تغییر یافته به همراه85 افزوده شده و 4 حذف شده
  1. 7 0
      Kernel/Arch/aarch64/Dummy.cpp
  2. 2 0
      Kernel/CMakeLists.txt
  3. 68 2
      Kernel/Time/TimeManagement.cpp
  4. 8 2
      Kernel/Time/TimeManagement.h

+ 7 - 0
Kernel/Arch/aarch64/Dummy.cpp

@@ -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 };
 
 

+ 2 - 0
Kernel/CMakeLists.txt

@@ -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
 
 

+ 68 - 2
Kernel/Time/TimeManagement.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()
 {
 {

+ 8 - 2
Kernel/Time/TimeManagement.h

@@ -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 };