mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 22:02:44 +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
	
	 Timon Kruiper
						Timon Kruiper