HPET.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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/StringView.h>
  27. #include <Kernel/ACPI/Parser.h>
  28. #include <Kernel/Interrupts/InterruptManagement.h>
  29. #include <Kernel/Time/HPET.h>
  30. #include <Kernel/Time/HPETComparator.h>
  31. #include <Kernel/Time/TimeManagement.h>
  32. #include <Kernel/VM/MemoryManager.h>
  33. #include <Kernel/VM/TypedMapping.h>
  34. namespace Kernel {
  35. #define ABSOLUTE_MAXIMUM_COUNTER_TICK_PERIOD 0x05F5E100
  36. #define NANOSECOND_PERIOD_TO_HERTZ(x) 1000000000 / x
  37. #define MEGAHERTZ_TO_HERTZ(x) (x / 1000000)
  38. //#define HPET_DEBUG
  39. namespace HPETFlags {
  40. enum class Attributes {
  41. Counter64BitCapable = 1 << 13,
  42. LegacyReplacementRouteCapable = 1 << 15
  43. };
  44. enum class Configuration {
  45. Enable = 0x1,
  46. LegacyReplacementRoute = 0x2
  47. };
  48. enum class TimerConfiguration : u32 {
  49. InterruptType = 1 << 1,
  50. InterruptEnable = 1 << 2,
  51. TimerType = 1 << 3,
  52. PeriodicInterruptCapable = 1 << 4,
  53. Timer64BitsCapable = 1 << 5,
  54. ValueSet = 1 << 6,
  55. Force32BitMode = 1 << 7,
  56. FSBInterruptEnable = 1 << 14,
  57. FSBInterruptDelivery = 1 << 15
  58. };
  59. };
  60. struct [[gnu::packed]] TimerStructure
  61. {
  62. u64 configuration_and_capability;
  63. u64 comparator_value;
  64. u64 fsb_interrupt_route;
  65. u64 reserved;
  66. };
  67. struct [[gnu::packed]] HPETCapabilityRegister
  68. {
  69. u32 attributes; // Note: We must do a 32 bit access to offsets 0x0, or 0x4 only, according to HPET spec.
  70. u32 main_counter_tick_period;
  71. u64 reserved;
  72. };
  73. struct [[gnu::packed]] HPETRegister
  74. {
  75. u64 reg;
  76. u64 reserved;
  77. };
  78. struct [[gnu::packed]] HPETRegistersBlock
  79. {
  80. union {
  81. HPETCapabilityRegister capabilities;
  82. HPETRegister raw_capabilites;
  83. };
  84. HPETRegister configuration;
  85. HPETRegister interrupt_status;
  86. u8 reserved[0xF0 - 48];
  87. HPETRegister main_counter_value;
  88. TimerStructure timers[3];
  89. u8 reserved2[0x400 - 0x160];
  90. };
  91. static HPET* s_hpet;
  92. static bool hpet_initialized { false };
  93. bool HPET::initialized()
  94. {
  95. return hpet_initialized;
  96. }
  97. HPET& HPET::the()
  98. {
  99. ASSERT(HPET::initialized());
  100. ASSERT(s_hpet != nullptr);
  101. return *s_hpet;
  102. }
  103. bool HPET::test_and_initialize()
  104. {
  105. ASSERT(!HPET::initialized());
  106. hpet_initialized = true;
  107. auto hpet = ACPI::Parser::the()->find_table("HPET");
  108. if (hpet.is_null())
  109. return false;
  110. klog() << "HPET @ " << hpet;
  111. auto sdt = map_typed<ACPI::Structures::HPET>(hpet);
  112. // Note: HPET is only usable from System Memory
  113. ASSERT(sdt->event_timer_block.address_space == (u8)ACPI::GenericAddressStructure::AddressSpace::SystemMemory);
  114. if (TimeManagement::is_hpet_periodic_mode_allowed()) {
  115. if (!check_for_exisiting_periodic_timers()) {
  116. dbg() << "HPET: No periodic capable timers";
  117. return false;
  118. }
  119. }
  120. s_hpet = new HPET(PhysicalAddress(hpet));
  121. return true;
  122. }
  123. bool HPET::check_for_exisiting_periodic_timers()
  124. {
  125. auto hpet = ACPI::Parser::the()->find_table("HPET");
  126. if (hpet.is_null())
  127. return false;
  128. auto sdt = map_typed<ACPI::Structures::HPET>(hpet);
  129. ASSERT(sdt->event_timer_block.address_space == 0);
  130. auto registers = map_typed<volatile HPETRegistersBlock>(PhysicalAddress(sdt->event_timer_block.address));
  131. size_t timers_count = ((registers->raw_capabilites.reg >> 8) & 0x1f) + 1;
  132. for (size_t index = 0; index < timers_count; index++) {
  133. if (registers->timers[index].configuration_and_capability & (u32)HPETFlags::TimerConfiguration::PeriodicInterruptCapable)
  134. return true;
  135. }
  136. return false;
  137. }
  138. void HPET::global_disable()
  139. {
  140. registers().configuration.reg = registers().configuration.reg & ~(u32)HPETFlags::Configuration::Enable;
  141. }
  142. void HPET::global_enable()
  143. {
  144. registers().configuration.reg = registers().configuration.reg | (u32)HPETFlags::Configuration::Enable;
  145. }
  146. void HPET::set_periodic_comparator_value(const HPETComparator& comparator, u64 value)
  147. {
  148. disable(comparator);
  149. ASSERT(comparator.is_periodic());
  150. ASSERT(comparator.comparator_number() <= m_comparators.size());
  151. volatile auto& timer = registers().timers[comparator.comparator_number()];
  152. timer.configuration_and_capability = timer.configuration_and_capability | (u32)HPETFlags::TimerConfiguration::ValueSet;
  153. timer.comparator_value = value;
  154. enable(comparator);
  155. }
  156. void HPET::set_non_periodic_comparator_value(const HPETComparator& comparator, u64 value)
  157. {
  158. ASSERT_INTERRUPTS_DISABLED();
  159. ASSERT(!comparator.is_periodic());
  160. ASSERT(comparator.comparator_number() <= m_comparators.size());
  161. registers().timers[comparator.comparator_number()].comparator_value = main_counter_value() + value;
  162. }
  163. void HPET::enable_periodic_interrupt(const HPETComparator& comparator)
  164. {
  165. #ifdef HPET_DEBUG
  166. klog() << "HPET: Set comparator " << comparator.comparator_number() << " to be periodic.";
  167. #endif
  168. disable(comparator);
  169. ASSERT(comparator.comparator_number() <= m_comparators.size());
  170. volatile auto& timer = registers().timers[comparator.comparator_number()];
  171. auto configuration_and_capability = timer.configuration_and_capability;
  172. ASSERT(configuration_and_capability & (u32)HPETFlags::TimerConfiguration::PeriodicInterruptCapable);
  173. timer.configuration_and_capability = configuration_and_capability | (u32)HPETFlags::TimerConfiguration::TimerType;
  174. enable(comparator);
  175. }
  176. void HPET::disable_periodic_interrupt(const HPETComparator& comparator)
  177. {
  178. #ifdef HPET_DEBUG
  179. klog() << "HPET: Disable periodic interrupt in comparator " << comparator.comparator_number() << ".";
  180. #endif
  181. disable(comparator);
  182. ASSERT(comparator.comparator_number() <= m_comparators.size());
  183. auto volatile& timer = registers().timers[comparator.comparator_number()];
  184. auto configuration_and_capability = timer.configuration_and_capability;
  185. ASSERT(configuration_and_capability & (u32)HPETFlags::TimerConfiguration::PeriodicInterruptCapable);
  186. timer.configuration_and_capability = configuration_and_capability & ~(u32)HPETFlags::TimerConfiguration::TimerType;
  187. enable(comparator);
  188. }
  189. void HPET::disable(const HPETComparator& comparator)
  190. {
  191. #ifdef HPET_DEBUG
  192. klog() << "HPET: Disable comparator " << comparator.comparator_number() << ".";
  193. #endif
  194. ASSERT(comparator.comparator_number() <= m_comparators.size());
  195. volatile auto& timer = registers().timers[comparator.comparator_number()];
  196. timer.configuration_and_capability = timer.configuration_and_capability & ~(u32)HPETFlags::TimerConfiguration::InterruptEnable;
  197. }
  198. void HPET::enable(const HPETComparator& comparator)
  199. {
  200. #ifdef HPET_DEBUG
  201. klog() << "HPET: Enable comparator " << comparator.comparator_number() << ".";
  202. #endif
  203. ASSERT(comparator.comparator_number() <= m_comparators.size());
  204. volatile auto& timer = registers().timers[comparator.comparator_number()];
  205. timer.configuration_and_capability = timer.configuration_and_capability | (u32)HPETFlags::TimerConfiguration::InterruptEnable;
  206. }
  207. u64 HPET::main_counter_value() const
  208. {
  209. return registers().main_counter_value.reg;
  210. }
  211. u64 HPET::frequency() const
  212. {
  213. return m_frequency;
  214. }
  215. Vector<unsigned> HPET::capable_interrupt_numbers(const HPETComparator& comparator)
  216. {
  217. ASSERT(comparator.comparator_number() <= m_comparators.size());
  218. Vector<unsigned> capable_interrupts;
  219. auto& comparator_registers = (const volatile TimerStructure&)registers().timers[comparator.comparator_number()];
  220. u32 interrupt_bitfield = comparator_registers.configuration_and_capability >> 32;
  221. for (size_t index = 0; index < 32; index++) {
  222. if (interrupt_bitfield & 1)
  223. capable_interrupts.append(index);
  224. interrupt_bitfield >>= 1;
  225. }
  226. return capable_interrupts;
  227. }
  228. Vector<unsigned> HPET::capable_interrupt_numbers(u8 comparator_number)
  229. {
  230. ASSERT(comparator_number <= m_comparators.size());
  231. Vector<unsigned> capable_interrupts;
  232. auto& comparator_registers = (const volatile TimerStructure&)registers().timers[comparator_number];
  233. u32 interrupt_bitfield = comparator_registers.configuration_and_capability >> 32;
  234. for (size_t index = 0; index < 32; index++) {
  235. if (interrupt_bitfield & 1)
  236. capable_interrupts.append(index);
  237. interrupt_bitfield >>= 1;
  238. }
  239. return capable_interrupts;
  240. }
  241. void HPET::set_comparator_irq_vector(u8 comparator_number, u8 irq_vector)
  242. {
  243. ASSERT(comparator_number <= m_comparators.size());
  244. auto& comparator_registers = (volatile TimerStructure&)registers().timers[comparator_number];
  245. comparator_registers.configuration_and_capability = comparator_registers.configuration_and_capability | (irq_vector << 9);
  246. }
  247. bool HPET::is_periodic_capable(u8 comparator_number) const
  248. {
  249. ASSERT(comparator_number <= m_comparators.size());
  250. auto& comparator_registers = (const volatile TimerStructure&)registers().timers[comparator_number];
  251. return comparator_registers.configuration_and_capability & (u32)HPETFlags::TimerConfiguration::PeriodicInterruptCapable;
  252. }
  253. void HPET::set_comparators_to_optimal_interrupt_state(size_t)
  254. {
  255. // FIXME: Implement this method for allowing to use HPET timers 2-31...
  256. ASSERT_NOT_REACHED();
  257. }
  258. PhysicalAddress HPET::find_acpi_hpet_registers_block()
  259. {
  260. auto sdt = map_typed<const volatile ACPI::Structures::HPET>(m_physical_acpi_hpet_table);
  261. ASSERT(sdt->event_timer_block.address_space == (u8)ACPI::GenericAddressStructure::AddressSpace::SystemMemory);
  262. return PhysicalAddress(sdt->event_timer_block.address);
  263. }
  264. const volatile HPETRegistersBlock& HPET::registers() const
  265. {
  266. return *(const volatile HPETRegistersBlock*)m_hpet_mmio_region->vaddr().offset(m_physical_acpi_hpet_registers.offset_in_page()).as_ptr();
  267. }
  268. volatile HPETRegistersBlock& HPET::registers()
  269. {
  270. return *(volatile HPETRegistersBlock*)m_hpet_mmio_region->vaddr().offset(m_physical_acpi_hpet_registers.offset_in_page()).as_ptr();
  271. }
  272. u64 HPET::calculate_ticks_in_nanoseconds() const
  273. {
  274. return ABSOLUTE_MAXIMUM_COUNTER_TICK_PERIOD / registers().capabilities.main_counter_tick_period;
  275. }
  276. HPET::HPET(PhysicalAddress acpi_hpet)
  277. : m_physical_acpi_hpet_table(acpi_hpet)
  278. , m_physical_acpi_hpet_registers(find_acpi_hpet_registers_block())
  279. , 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))
  280. {
  281. auto sdt = map_typed<const volatile ACPI::Structures::HPET>(m_physical_acpi_hpet_table);
  282. m_vendor_id = sdt->pci_vendor_id;
  283. m_minimum_tick = sdt->mininum_clock_tick;
  284. klog() << "HPET: Minimum clock tick - " << m_minimum_tick;
  285. // Note: We must do a 32 bit access to offsets 0x0, or 0x4 only.
  286. size_t timers_count = ((registers().raw_capabilites.reg >> 8) & 0x1f) + 1;
  287. klog() << "HPET: Timers count - " << timers_count;
  288. ASSERT(timers_count >= 2);
  289. auto* capabilities_register = (const volatile HPETCapabilityRegister*)&registers().raw_capabilites.reg;
  290. global_disable();
  291. m_frequency = NANOSECOND_PERIOD_TO_HERTZ(calculate_ticks_in_nanoseconds());
  292. klog() << "HPET: frequency " << m_frequency << " Hz (" << MEGAHERTZ_TO_HERTZ(m_frequency) << " MHz)";
  293. ASSERT(capabilities_register->main_counter_tick_period <= ABSOLUTE_MAXIMUM_COUNTER_TICK_PERIOD);
  294. // Reset the counter, just in case...
  295. registers().main_counter_value.reg = 0;
  296. if (registers().raw_capabilites.reg & (u32)HPETFlags::Attributes::LegacyReplacementRouteCapable)
  297. registers().configuration.reg = registers().configuration.reg | (u32)HPETFlags::Configuration::LegacyReplacementRoute;
  298. m_comparators.append(HPETComparator::create(0, 0, is_periodic_capable(0)));
  299. m_comparators.append(HPETComparator::create(1, 8, is_periodic_capable(1)));
  300. global_enable();
  301. }
  302. }