TimeManagement.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include <AK/Singleton.h>
  27. #include <AK/Time.h>
  28. #include <Kernel/ACPI/Parser.h>
  29. #include <Kernel/CommandLine.h>
  30. #include <Kernel/Interrupts/APIC.h>
  31. #include <Kernel/Scheduler.h>
  32. #include <Kernel/Time/APICTimer.h>
  33. #include <Kernel/Time/HPET.h>
  34. #include <Kernel/Time/HPETComparator.h>
  35. #include <Kernel/Time/HardwareTimer.h>
  36. #include <Kernel/Time/PIT.h>
  37. #include <Kernel/Time/RTC.h>
  38. #include <Kernel/Time/TimeManagement.h>
  39. #include <Kernel/VM/MemoryManager.h>
  40. //#define TIME_DEBUG
  41. namespace Kernel {
  42. static AK::Singleton<TimeManagement> s_the;
  43. TimeManagement& TimeManagement::the()
  44. {
  45. return *s_the;
  46. }
  47. bool TimeManagement::is_system_timer(const HardwareTimerBase& timer) const
  48. {
  49. return &timer == m_system_timer.ptr();
  50. }
  51. void TimeManagement::set_epoch_time(timespec ts)
  52. {
  53. timespec ticks = { 0, (long)ticks_this_second() * (long)1'000'000 };
  54. timespec_sub(ts, ticks, ts);
  55. InterruptDisabler disabler;
  56. m_epoch_time = ts;
  57. }
  58. timespec TimeManagement::epoch_time() const
  59. {
  60. timespec ts = m_epoch_time;
  61. timespec ticks = { 0, (long)ticks_this_second() * (long)1'000'000 };
  62. timespec_add(ts, ticks, ts);
  63. return ts;
  64. }
  65. void TimeManagement::initialize(u32 cpu)
  66. {
  67. if (cpu == 0) {
  68. ASSERT(!s_the.is_initialized());
  69. s_the.ensure_instance();
  70. // Initialize the APIC timers after the other timers as the
  71. // initialization needs to briefly enable interrupts, which then
  72. // would trigger a deadlock trying to get the s_the instance while
  73. // creating it.
  74. if (auto* apic_timer = APIC::the().initialize_timers(*s_the->m_system_timer)) {
  75. klog() << "Time: Using APIC timer as system timer";
  76. s_the->set_system_timer(*apic_timer);
  77. }
  78. } else {
  79. ASSERT(s_the.is_initialized());
  80. if (auto* apic_timer = APIC::the().get_timer()) {
  81. klog() << "Time: Enable APIC timer on CPU #" << cpu;
  82. apic_timer->enable_local_timer();
  83. }
  84. }
  85. }
  86. void TimeManagement::set_system_timer(HardwareTimerBase& timer)
  87. {
  88. auto original_callback = m_system_timer->set_callback(nullptr);
  89. timer.set_callback(move(original_callback));
  90. m_system_timer = timer;
  91. }
  92. time_t TimeManagement::seconds_since_boot() const
  93. {
  94. return m_seconds_since_boot;
  95. }
  96. time_t TimeManagement::ticks_per_second() const
  97. {
  98. return m_system_timer->ticks_per_second();
  99. }
  100. time_t TimeManagement::ticks_this_second() const
  101. {
  102. return m_ticks_this_second;
  103. }
  104. time_t TimeManagement::boot_time() const
  105. {
  106. return RTC::boot_time();
  107. }
  108. TimeManagement::TimeManagement()
  109. {
  110. bool probe_non_legacy_hardware_timers = !(kernel_command_line().lookup("time").value_or("modern") == "legacy");
  111. if (ACPI::is_enabled()) {
  112. if (!ACPI::Parser::the()->x86_specific_flags().cmos_rtc_not_present) {
  113. RTC::initialize();
  114. m_epoch_time.tv_sec += boot_time();
  115. } else {
  116. klog() << "ACPI: RTC CMOS Not present";
  117. }
  118. } else {
  119. // We just assume that we can access RTC CMOS, if ACPI isn't usable.
  120. RTC::initialize();
  121. m_epoch_time.tv_sec += boot_time();
  122. }
  123. if (probe_non_legacy_hardware_timers) {
  124. if (!probe_and_set_non_legacy_hardware_timers())
  125. if (!probe_and_set_legacy_hardware_timers())
  126. ASSERT_NOT_REACHED();
  127. } else if (!probe_and_set_legacy_hardware_timers()) {
  128. ASSERT_NOT_REACHED();
  129. }
  130. }
  131. timeval TimeManagement::now_as_timeval()
  132. {
  133. timespec ts = s_the.ptr()->epoch_time();
  134. timeval tv;
  135. timespec_to_timeval(ts, tv);
  136. return tv;
  137. }
  138. Vector<HardwareTimerBase*> TimeManagement::scan_and_initialize_periodic_timers()
  139. {
  140. bool should_enable = is_hpet_periodic_mode_allowed();
  141. dbg() << "Time: Scanning for periodic timers";
  142. Vector<HardwareTimerBase*> timers;
  143. for (auto& hardware_timer : m_hardware_timers) {
  144. if (hardware_timer.is_periodic_capable()) {
  145. timers.append(&hardware_timer);
  146. if (should_enable)
  147. hardware_timer.set_periodic();
  148. }
  149. }
  150. return timers;
  151. }
  152. Vector<HardwareTimerBase*> TimeManagement::scan_for_non_periodic_timers()
  153. {
  154. dbg() << "Time: Scanning for non-periodic timers";
  155. Vector<HardwareTimerBase*> timers;
  156. for (auto& hardware_timer : m_hardware_timers) {
  157. if (!hardware_timer.is_periodic_capable())
  158. timers.append(&hardware_timer);
  159. }
  160. return timers;
  161. }
  162. bool TimeManagement::is_hpet_periodic_mode_allowed()
  163. {
  164. auto hpet_mode = kernel_command_line().lookup("hpet").value_or("periodic");
  165. if (hpet_mode == "periodic")
  166. return true;
  167. if (hpet_mode == "nonperiodic")
  168. return false;
  169. ASSERT_NOT_REACHED();
  170. }
  171. bool TimeManagement::probe_and_set_non_legacy_hardware_timers()
  172. {
  173. if (!ACPI::is_enabled())
  174. return false;
  175. if (!HPET::test_and_initialize())
  176. return false;
  177. if (!HPET::the().comparators().size()) {
  178. dbg() << "HPET initialization aborted.";
  179. return false;
  180. }
  181. dbg() << "HPET: Setting appropriate functions to timers.";
  182. for (auto& hpet_comparator : HPET::the().comparators())
  183. m_hardware_timers.append(hpet_comparator);
  184. auto periodic_timers = scan_and_initialize_periodic_timers();
  185. auto non_periodic_timers = scan_for_non_periodic_timers();
  186. if (is_hpet_periodic_mode_allowed())
  187. ASSERT(!periodic_timers.is_empty());
  188. ASSERT(periodic_timers.size() + non_periodic_timers.size() >= 2);
  189. if (periodic_timers.size() >= 2) {
  190. m_time_keeper_timer = periodic_timers[1];
  191. m_system_timer = periodic_timers[0];
  192. } else {
  193. if (periodic_timers.size() == 1) {
  194. m_time_keeper_timer = periodic_timers[0];
  195. m_system_timer = non_periodic_timers[0];
  196. } else {
  197. m_time_keeper_timer = non_periodic_timers[1];
  198. m_system_timer = non_periodic_timers[0];
  199. }
  200. }
  201. m_system_timer->set_callback(Scheduler::timer_tick);
  202. m_time_keeper_timer->set_callback(TimeManagement::update_time);
  203. dbg() << "Reset timers";
  204. m_system_timer->try_to_set_frequency(m_system_timer->calculate_nearest_possible_frequency(1024));
  205. m_time_keeper_timer->try_to_set_frequency(OPTIMAL_TICKS_PER_SECOND_RATE);
  206. return true;
  207. }
  208. bool TimeManagement::probe_and_set_legacy_hardware_timers()
  209. {
  210. if (ACPI::is_enabled()) {
  211. if (ACPI::Parser::the()->x86_specific_flags().cmos_rtc_not_present) {
  212. dbg() << "ACPI: CMOS RTC Not Present";
  213. return false;
  214. } else {
  215. dbg() << "ACPI: CMOS RTC Present";
  216. }
  217. }
  218. m_hardware_timers.append(PIT::initialize(TimeManagement::update_time));
  219. m_hardware_timers.append(RealTimeClock::create(Scheduler::timer_tick));
  220. m_time_keeper_timer = m_hardware_timers[0];
  221. m_system_timer = m_hardware_timers[1];
  222. return true;
  223. }
  224. void TimeManagement::update_time(const RegisterState& regs)
  225. {
  226. TimeManagement::the().increment_time_since_boot(regs);
  227. }
  228. void TimeManagement::increment_time_since_boot(const RegisterState&)
  229. {
  230. ASSERT(!m_time_keeper_timer.is_null());
  231. if (++m_ticks_this_second >= m_time_keeper_timer->ticks_per_second()) {
  232. // FIXME: Synchronize with other clock somehow to prevent drifting apart.
  233. ++m_seconds_since_boot;
  234. ++m_epoch_time.tv_sec;
  235. m_ticks_this_second = 0;
  236. }
  237. }
  238. }