HPET.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  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/Debug.h>
  27. #include <AK/StringView.h>
  28. #include <Kernel/ACPI/Parser.h>
  29. #include <Kernel/Interrupts/InterruptManagement.h>
  30. #include <Kernel/Time/HPET.h>
  31. #include <Kernel/Time/HPETComparator.h>
  32. #include <Kernel/Time/TimeManagement.h>
  33. #include <Kernel/VM/MemoryManager.h>
  34. #include <Kernel/VM/TypedMapping.h>
  35. namespace Kernel {
  36. #define ABSOLUTE_MAXIMUM_COUNTER_TICK_PERIOD 0x05F5E100
  37. #define NANOSECOND_PERIOD_TO_HERTZ(x) 1000000000 / x
  38. #define MEGAHERTZ_TO_HERTZ(x) (x / 1000000)
  39. namespace HPETFlags {
  40. enum class Attributes {
  41. Counter64BitCapable = 1 << 13,
  42. LegacyReplacementRouteCapable = 1 << 15
  43. };
  44. enum class Configuration {
  45. Enable = 1 << 0,
  46. LegacyReplacementRoute = 1 << 1
  47. };
  48. enum class TimerConfiguration : u32 {
  49. LevelTriggered = 1 << 1,
  50. InterruptEnable = 1 << 2,
  51. GeneratePeriodicInterrupt = 1 << 3,
  52. PeriodicInterruptCapable = 1 << 4,
  53. Timer64BitsCapable = 1 << 5,
  54. ValueSet = 1 << 6,
  55. Force32BitMode = 1 << 8,
  56. FSBInterruptEnable = 1 << 14,
  57. FSBInterruptDelivery = 1 << 15
  58. };
  59. };
  60. struct [[gnu::packed]] HPETRegister {
  61. volatile u32 low;
  62. volatile u32 high;
  63. };
  64. struct [[gnu::packed]] TimerStructure {
  65. volatile u32 capabilities;
  66. volatile u32 interrupt_routing;
  67. HPETRegister comparator_value;
  68. volatile u64 fsb_interrupt_route;
  69. u64 reserved;
  70. };
  71. struct [[gnu::packed]] HPETCapabilityRegister {
  72. // Note: We must do a 32 bit access to offsets 0x0, or 0x4 only, according to HPET spec.
  73. volatile u32 attributes;
  74. volatile u32 main_counter_tick_period;
  75. u64 reserved;
  76. };
  77. struct [[gnu::packed]] HPETRegistersBlock {
  78. HPETCapabilityRegister capabilities;
  79. HPETRegister configuration;
  80. u64 reserved1;
  81. HPETRegister interrupt_status;
  82. u8 reserved2[0xF0 - 0x28];
  83. HPETRegister main_counter_value;
  84. u64 reserved3;
  85. TimerStructure timers[3];
  86. u8 reserved4[0x400 - 0x160];
  87. };
  88. static_assert(__builtin_offsetof(HPETRegistersBlock, main_counter_value) == 0xf0);
  89. static_assert(__builtin_offsetof(HPETRegistersBlock, timers[0]) == 0x100);
  90. static_assert(__builtin_offsetof(HPETRegistersBlock, timers[1]) == 0x120);
  91. static u64 read_register_safe64(const HPETRegister& reg)
  92. {
  93. // As per 2.4.7 this reads the 64 bit value in a consistent manner
  94. // using only 32 bit reads
  95. u32 low, high = reg.high;
  96. for (;;) {
  97. low = reg.low;
  98. u32 new_high = reg.high;
  99. if (new_high == high)
  100. break;
  101. high = new_high;
  102. }
  103. return ((u64)high << 32) | (u64)low;
  104. }
  105. static HPET* s_hpet;
  106. static bool hpet_initialized { false };
  107. bool HPET::initialized()
  108. {
  109. return hpet_initialized;
  110. }
  111. HPET& HPET::the()
  112. {
  113. ASSERT(HPET::initialized());
  114. ASSERT(s_hpet != nullptr);
  115. return *s_hpet;
  116. }
  117. bool HPET::test_and_initialize()
  118. {
  119. ASSERT(!HPET::initialized());
  120. hpet_initialized = true;
  121. auto hpet = ACPI::Parser::the()->find_table("HPET");
  122. if (hpet.is_null())
  123. return false;
  124. klog() << "HPET @ " << hpet;
  125. auto sdt = map_typed<ACPI::Structures::HPET>(hpet);
  126. // Note: HPET is only usable from System Memory
  127. ASSERT(sdt->event_timer_block.address_space == (u8)ACPI::GenericAddressStructure::AddressSpace::SystemMemory);
  128. if (TimeManagement::is_hpet_periodic_mode_allowed()) {
  129. if (!check_for_exisiting_periodic_timers()) {
  130. dbgln("HPET: No periodic capable timers");
  131. return false;
  132. }
  133. }
  134. new HPET(PhysicalAddress(hpet));
  135. return true;
  136. }
  137. bool HPET::check_for_exisiting_periodic_timers()
  138. {
  139. auto hpet = ACPI::Parser::the()->find_table("HPET");
  140. if (hpet.is_null())
  141. return false;
  142. auto sdt = map_typed<ACPI::Structures::HPET>(hpet);
  143. ASSERT(sdt->event_timer_block.address_space == 0);
  144. auto registers = map_typed<HPETRegistersBlock>(PhysicalAddress(sdt->event_timer_block.address));
  145. size_t timers_count = ((registers->capabilities.attributes >> 8) & 0x1f) + 1;
  146. for (size_t index = 0; index < timers_count; index++) {
  147. if (registers->timers[index].capabilities & (u32)HPETFlags::TimerConfiguration::PeriodicInterruptCapable)
  148. return true;
  149. }
  150. return false;
  151. }
  152. void HPET::global_disable()
  153. {
  154. auto& regs = registers();
  155. regs.configuration.low = regs.configuration.low & ~(u32)HPETFlags::Configuration::Enable;
  156. }
  157. void HPET::global_enable()
  158. {
  159. auto& regs = registers();
  160. regs.configuration.low = regs.configuration.low | (u32)HPETFlags::Configuration::Enable;
  161. }
  162. void HPET::update_periodic_comparator_value()
  163. {
  164. // According to 2.3.9.2.2 the only safe way to change the periodic timer frequency
  165. // is to disable all periodic timers, reset the main counter and each timer's comparator value.
  166. // This introduces time drift, so it should be avoided unless absolutely necessary.
  167. global_disable();
  168. auto& regs = registers();
  169. u64 previous_main_value = (u64)regs.main_counter_value.low | ((u64)regs.main_counter_value.high << 32);
  170. m_main_counter_drift += previous_main_value - m_main_counter_last_read;
  171. m_main_counter_last_read = 0;
  172. regs.main_counter_value.low = 0;
  173. regs.main_counter_value.high = 0;
  174. for (auto& comparator : m_comparators) {
  175. auto& timer = regs.timers[comparator.comparator_number()];
  176. if (!comparator.is_enabled())
  177. continue;
  178. if (comparator.is_periodic()) {
  179. // Note that this means we're restarting all periodic timers. There is no
  180. // way to resume periodic timers properly because we reset the main counter
  181. // and we can only write the period into the comparator value...
  182. timer.capabilities = timer.capabilities | (u32)HPETFlags::TimerConfiguration::ValueSet;
  183. u64 value = frequency() / comparator.ticks_per_second();
  184. dbgln<HPET_DEBUG>("HPET: Update periodic comparator {} comparator value to {} main value was: {}",
  185. comparator.comparator_number(),
  186. value,
  187. previous_main_value);
  188. timer.comparator_value.low = (u32)value;
  189. timer.capabilities = timer.capabilities | (u32)HPETFlags::TimerConfiguration::ValueSet;
  190. timer.comparator_value.high = (u32)(value >> 32);
  191. } else {
  192. // Set the new target comparator value to the delta to the remaining ticks
  193. u64 current_value = (u64)timer.comparator_value.low | ((u64)timer.comparator_value.high << 32);
  194. u64 value = current_value - previous_main_value;
  195. dbgln<HPET_DEBUG>("HPET: Update non-periodic comparator {} comparator value from {} to {} main value was: {}",
  196. comparator.comparator_number(),
  197. current_value,
  198. value,
  199. previous_main_value);
  200. timer.comparator_value.low = (u32)value;
  201. timer.comparator_value.high = (u32)(value >> 32);
  202. }
  203. }
  204. global_enable();
  205. }
  206. void HPET::update_non_periodic_comparator_value(const HPETComparator& comparator)
  207. {
  208. ASSERT_INTERRUPTS_DISABLED();
  209. ASSERT(!comparator.is_periodic());
  210. ASSERT(comparator.comparator_number() <= m_comparators.size());
  211. auto& regs = registers();
  212. auto& timer = regs.timers[comparator.comparator_number()];
  213. u64 value = frequency() / comparator.ticks_per_second();
  214. // NOTE: If the main counter passes this new value before we finish writing it, we will never receive an interrupt!
  215. u64 new_counter_value = read_register_safe64(regs.main_counter_value) + value;
  216. timer.comparator_value.high = (u32)(new_counter_value >> 32);
  217. timer.comparator_value.low = (u32)new_counter_value;
  218. }
  219. u64 HPET::update_time(u64& seconds_since_boot, u32& ticks_this_second, bool query_only)
  220. {
  221. // Should only be called by the time keeper interrupt handler!
  222. u64 current_value = read_register_safe64(registers().main_counter_value);
  223. u64 delta_ticks = m_main_counter_drift;
  224. if (current_value >= m_main_counter_last_read)
  225. delta_ticks += current_value - m_main_counter_last_read;
  226. else
  227. delta_ticks += m_main_counter_last_read - current_value; // the counter wrapped around
  228. u64 ticks_since_last_second = (u64)ticks_this_second + delta_ticks;
  229. auto ticks_per_second = frequency();
  230. if (ticks_since_last_second >= ticks_per_second) {
  231. seconds_since_boot += ticks_since_last_second / ticks_per_second;
  232. ticks_this_second = ticks_since_last_second % ticks_per_second;
  233. } else {
  234. ticks_this_second = ticks_since_last_second;
  235. }
  236. if (!query_only) {
  237. m_main_counter_drift = 0;
  238. m_main_counter_last_read = current_value;
  239. }
  240. // Return the time passed (in ns) since last time update_time was called
  241. return (delta_ticks * 1000000000ull) / ticks_per_second;
  242. }
  243. u64 HPET::read_main_counter() const
  244. {
  245. auto& main_counter = registers().main_counter_value;
  246. return ((u64)main_counter.high << 32) | (u64)main_counter.low;
  247. }
  248. void HPET::enable_periodic_interrupt(const HPETComparator& comparator)
  249. {
  250. #if HPET_DEBUG
  251. klog() << "HPET: Set comparator " << comparator.comparator_number() << " to be periodic.";
  252. #endif
  253. disable(comparator);
  254. ASSERT(comparator.comparator_number() <= m_comparators.size());
  255. auto& timer = registers().timers[comparator.comparator_number()];
  256. auto capabilities = timer.capabilities;
  257. ASSERT(capabilities & (u32)HPETFlags::TimerConfiguration::PeriodicInterruptCapable);
  258. timer.capabilities = capabilities | (u32)HPETFlags::TimerConfiguration::GeneratePeriodicInterrupt;
  259. if (comparator.is_enabled())
  260. enable(comparator);
  261. }
  262. void HPET::disable_periodic_interrupt(const HPETComparator& comparator)
  263. {
  264. #if HPET_DEBUG
  265. klog() << "HPET: Disable periodic interrupt in comparator " << comparator.comparator_number() << ".";
  266. #endif
  267. disable(comparator);
  268. ASSERT(comparator.comparator_number() <= m_comparators.size());
  269. auto& timer = registers().timers[comparator.comparator_number()];
  270. auto capabilities = timer.capabilities;
  271. ASSERT(capabilities & (u32)HPETFlags::TimerConfiguration::PeriodicInterruptCapable);
  272. timer.capabilities = capabilities & ~(u32)HPETFlags::TimerConfiguration::GeneratePeriodicInterrupt;
  273. if (comparator.is_enabled())
  274. enable(comparator);
  275. }
  276. void HPET::disable(const HPETComparator& comparator)
  277. {
  278. #if HPET_DEBUG
  279. klog() << "HPET: Disable comparator " << comparator.comparator_number() << ".";
  280. #endif
  281. ASSERT(comparator.comparator_number() <= m_comparators.size());
  282. auto& timer = registers().timers[comparator.comparator_number()];
  283. timer.capabilities = timer.capabilities & ~(u32)HPETFlags::TimerConfiguration::InterruptEnable;
  284. }
  285. void HPET::enable(const HPETComparator& comparator)
  286. {
  287. #if HPET_DEBUG
  288. klog() << "HPET: Enable comparator " << comparator.comparator_number() << ".";
  289. #endif
  290. ASSERT(comparator.comparator_number() <= m_comparators.size());
  291. auto& timer = registers().timers[comparator.comparator_number()];
  292. timer.capabilities = timer.capabilities | (u32)HPETFlags::TimerConfiguration::InterruptEnable;
  293. }
  294. Vector<unsigned> HPET::capable_interrupt_numbers(const HPETComparator& comparator)
  295. {
  296. ASSERT(comparator.comparator_number() <= m_comparators.size());
  297. Vector<unsigned> capable_interrupts;
  298. auto& comparator_registers = registers().timers[comparator.comparator_number()];
  299. u32 interrupt_bitfield = comparator_registers.interrupt_routing;
  300. for (size_t index = 0; index < 32; index++) {
  301. if (interrupt_bitfield & 1)
  302. capable_interrupts.append(index);
  303. interrupt_bitfield >>= 1;
  304. }
  305. return capable_interrupts;
  306. }
  307. Vector<unsigned> HPET::capable_interrupt_numbers(u8 comparator_number)
  308. {
  309. ASSERT(comparator_number <= m_comparators.size());
  310. Vector<unsigned> capable_interrupts;
  311. auto& comparator_registers = registers().timers[comparator_number];
  312. u32 interrupt_bitfield = comparator_registers.interrupt_routing;
  313. for (size_t index = 0; index < 32; index++) {
  314. if (interrupt_bitfield & 1)
  315. capable_interrupts.append(index);
  316. interrupt_bitfield >>= 1;
  317. }
  318. return capable_interrupts;
  319. }
  320. void HPET::set_comparator_irq_vector(u8 comparator_number, u8 irq_vector)
  321. {
  322. ASSERT(comparator_number <= m_comparators.size());
  323. auto& comparator_registers = registers().timers[comparator_number];
  324. comparator_registers.capabilities = comparator_registers.capabilities | (irq_vector << 9);
  325. }
  326. bool HPET::is_periodic_capable(u8 comparator_number) const
  327. {
  328. ASSERT(comparator_number <= m_comparators.size());
  329. auto& comparator_registers = registers().timers[comparator_number];
  330. return comparator_registers.capabilities & (u32)HPETFlags::TimerConfiguration::PeriodicInterruptCapable;
  331. }
  332. void HPET::set_comparators_to_optimal_interrupt_state(size_t)
  333. {
  334. // FIXME: Implement this method for allowing to use HPET timers 2-31...
  335. ASSERT_NOT_REACHED();
  336. }
  337. PhysicalAddress HPET::find_acpi_hpet_registers_block()
  338. {
  339. auto sdt = map_typed<const volatile ACPI::Structures::HPET>(m_physical_acpi_hpet_table);
  340. ASSERT(sdt->event_timer_block.address_space == (u8)ACPI::GenericAddressStructure::AddressSpace::SystemMemory);
  341. return PhysicalAddress(sdt->event_timer_block.address);
  342. }
  343. const HPETRegistersBlock& HPET::registers() const
  344. {
  345. return *(const HPETRegistersBlock*)m_hpet_mmio_region->vaddr().offset(m_physical_acpi_hpet_registers.offset_in_page()).as_ptr();
  346. }
  347. HPETRegistersBlock& HPET::registers()
  348. {
  349. return *(HPETRegistersBlock*)m_hpet_mmio_region->vaddr().offset(m_physical_acpi_hpet_registers.offset_in_page()).as_ptr();
  350. }
  351. u64 HPET::calculate_ticks_in_nanoseconds() const
  352. {
  353. // ABSOLUTE_MAXIMUM_COUNTER_TICK_PERIOD == 100 nanoseconds
  354. return ((u64)registers().capabilities.main_counter_tick_period * 100ull) / ABSOLUTE_MAXIMUM_COUNTER_TICK_PERIOD;
  355. }
  356. HPET::HPET(PhysicalAddress acpi_hpet)
  357. : m_physical_acpi_hpet_table(acpi_hpet)
  358. , m_physical_acpi_hpet_registers(find_acpi_hpet_registers_block())
  359. , m_hpet_mmio_region(MM.allocate_kernel_region(m_physical_acpi_hpet_registers.page_base(), PAGE_SIZE, "HPET MMIO", Region::Access::Read | Region::Access::Write))
  360. {
  361. s_hpet = this; // Make available as soon as possible so that IRQs can use it
  362. auto sdt = map_typed<const volatile ACPI::Structures::HPET>(m_physical_acpi_hpet_table);
  363. m_vendor_id = sdt->pci_vendor_id;
  364. m_minimum_tick = sdt->mininum_clock_tick;
  365. klog() << "HPET: Minimum clock tick - " << m_minimum_tick;
  366. auto& regs = registers();
  367. // Note: We must do a 32 bit access to offsets 0x0, or 0x4 only.
  368. size_t timers_count = ((regs.capabilities.attributes >> 8) & 0x1f) + 1;
  369. klog() << "HPET: Timers count - " << timers_count;
  370. klog() << "HPET: Main counter size: " << ((regs.capabilities.attributes & (u32)HPETFlags::Attributes::Counter64BitCapable) ? "64 bit" : "32 bit");
  371. for (size_t i = 0; i < timers_count; i++) {
  372. bool capable_64_bit = regs.timers[i].capabilities & (u32)HPETFlags::TimerConfiguration::Timer64BitsCapable;
  373. klog() << "HPET: Timer[" << i << "] comparator size: " << (capable_64_bit ? "64 bit" : "32 bit") << " mode: " << ((!capable_64_bit || (regs.timers[i].capabilities & (u32)HPETFlags::TimerConfiguration::Force32BitMode)) ? "32 bit" : "64 bit");
  374. }
  375. ASSERT(timers_count >= 2);
  376. global_disable();
  377. m_frequency = NANOSECOND_PERIOD_TO_HERTZ(calculate_ticks_in_nanoseconds());
  378. klog() << "HPET: frequency " << m_frequency << " Hz (" << MEGAHERTZ_TO_HERTZ(m_frequency) << " MHz) resolution: " << calculate_ticks_in_nanoseconds() << "ns";
  379. ASSERT(regs.capabilities.main_counter_tick_period <= ABSOLUTE_MAXIMUM_COUNTER_TICK_PERIOD);
  380. // Reset the counter, just in case... (needs to match m_main_counter_last_read)
  381. regs.main_counter_value.high = 0;
  382. regs.main_counter_value.low = 0;
  383. if (regs.capabilities.attributes & (u32)HPETFlags::Attributes::LegacyReplacementRouteCapable)
  384. regs.configuration.low = regs.configuration.low | (u32)HPETFlags::Configuration::LegacyReplacementRoute;
  385. m_comparators.append(HPETComparator::create(0, 0, is_periodic_capable(0)));
  386. m_comparators.append(HPETComparator::create(1, 8, is_periodic_capable(1)));
  387. global_enable();
  388. }
  389. }