Serenity Operating System
1/*
2 * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/Error.h>
10#include <AK/OwnPtr.h>
11#include <AK/Platform.h>
12#include <AK/Time.h>
13#include <AK/Types.h>
14#include <AK/Vector.h>
15#include <Kernel/API/TimePage.h>
16#include <Kernel/Arch/RegisterState.h>
17#include <Kernel/Forward.h>
18#include <Kernel/Library/LockRefPtr.h>
19#include <Kernel/UnixTypes.h>
20
21namespace Kernel {
22
23#define OPTIMAL_TICKS_PER_SECOND_RATE 250
24#define OPTIMAL_PROFILE_TICKS_PER_SECOND_RATE 1000
25
26class HardwareTimerBase;
27
28enum class TimePrecision {
29 Coarse = 0,
30 Precise
31};
32
33class TimeManagement {
34
35public:
36 TimeManagement();
37 static void initialize(u32 cpu);
38 static bool is_initialized();
39 static TimeManagement& the();
40
41 static u64 scheduler_current_time();
42
43 static ErrorOr<void> validate_clock_id(clockid_t);
44 Time current_time(clockid_t) const;
45 Time monotonic_time(TimePrecision = TimePrecision::Coarse) const;
46 Time monotonic_time_raw() const
47 {
48 // TODO: implement
49 return monotonic_time(TimePrecision::Precise);
50 }
51 Time epoch_time(TimePrecision = TimePrecision::Precise) const;
52 void set_epoch_time(Time);
53 time_t ticks_per_second() const;
54 static Time boot_time();
55 Time clock_resolution() const;
56
57 bool is_system_timer(HardwareTimerBase const&) const;
58
59 void increment_time_since_boot();
60
61 static bool is_hpet_periodic_mode_allowed();
62
63 bool enable_profile_timer();
64 bool disable_profile_timer();
65
66 u64 uptime_ms() const;
67 static Time now();
68
69 // FIXME: Should use AK::Time internally
70 // FIXME: Also, most likely broken, because it does not check m_update[12] for in-progress updates.
71 timespec remaining_epoch_time_adjustment() const { return m_remaining_epoch_time_adjustment; }
72 // FIXME: Should use AK::Time internally
73 // FIXME: Also, most likely broken, because it does not check m_update[12] for in-progress updates.
74 void set_remaining_epoch_time_adjustment(timespec const& adjustment) { m_remaining_epoch_time_adjustment = adjustment; }
75
76 bool can_query_precise_time() const { return m_can_query_precise_time; }
77
78 Memory::VMObject& time_page_vmobject();
79
80private:
81 TimePage& time_page();
82 void update_time_page();
83
84#if ARCH(X86_64)
85 bool probe_and_set_x86_legacy_hardware_timers();
86 bool probe_and_set_x86_non_legacy_hardware_timers();
87 void increment_time_since_boot_hpet();
88 static void update_time(RegisterState const&);
89#elif ARCH(AARCH64)
90 bool probe_and_set_aarch64_hardware_timers();
91#else
92# error Unknown architecture
93#endif
94 Vector<HardwareTimerBase*> scan_and_initialize_periodic_timers();
95 Vector<HardwareTimerBase*> scan_for_non_periodic_timers();
96 Vector<NonnullLockRefPtr<HardwareTimerBase>> m_hardware_timers;
97 void set_system_timer(HardwareTimerBase&);
98 static void system_timer_tick(RegisterState const&);
99
100 // Variables between m_update1 and m_update2 are synchronized
101 // FIXME: Replace m_update1 and m_update2 with a SpinlockLocker
102 Atomic<u32> m_update1 { 0 };
103 u32 m_ticks_this_second { 0 };
104 u64 m_seconds_since_boot { 0 };
105 // FIXME: Should use AK::Time internally
106 timespec m_epoch_time { 0, 0 };
107 timespec m_remaining_epoch_time_adjustment { 0, 0 };
108 Atomic<u32> m_update2 { 0 };
109
110 u32 m_time_ticks_per_second { 0 }; // may be different from interrupts/second (e.g. hpet)
111 bool m_can_query_precise_time { false };
112 bool m_updating_time { false }; // may only be accessed from the BSP!
113
114 LockRefPtr<HardwareTimerBase> m_system_timer;
115 LockRefPtr<HardwareTimerBase> m_time_keeper_timer;
116
117 Atomic<u32> m_profile_enable_count { 0 };
118 LockRefPtr<HardwareTimerBase> m_profile_timer;
119
120 NonnullOwnPtr<Memory::Region> m_time_page_region;
121};
122
123}