IO.h 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Assertions.h>
  8. #include <AK/String.h>
  9. #include <AK/Types.h>
  10. namespace IO {
  11. // Every character written to this IO port is written to the Bochs console
  12. // (e.g. the console where Qemu is running).
  13. static constexpr u16 BOCHS_DEBUG_PORT = 0xE9;
  14. inline u8 in8(u16 port)
  15. {
  16. u8 value;
  17. asm volatile("inb %1, %0"
  18. : "=a"(value)
  19. : "Nd"(port));
  20. return value;
  21. }
  22. inline u16 in16(u16 port)
  23. {
  24. u16 value;
  25. asm volatile("inw %1, %0"
  26. : "=a"(value)
  27. : "Nd"(port));
  28. return value;
  29. }
  30. inline u32 in32(u16 port)
  31. {
  32. u32 value;
  33. asm volatile("inl %1, %0"
  34. : "=a"(value)
  35. : "Nd"(port));
  36. return value;
  37. }
  38. inline void out8(u16 port, u8 value)
  39. {
  40. asm volatile("outb %0, %1" ::"a"(value), "Nd"(port));
  41. }
  42. inline void out16(u16 port, u16 value)
  43. {
  44. asm volatile("outw %0, %1" ::"a"(value), "Nd"(port));
  45. }
  46. inline void out32(u16 port, u32 value)
  47. {
  48. asm volatile("outl %0, %1" ::"a"(value), "Nd"(port));
  49. }
  50. inline void delay(size_t microseconds)
  51. {
  52. for (size_t i = 0; i < microseconds; ++i)
  53. IO::in8(0x80);
  54. }
  55. }
  56. class IOAddress {
  57. public:
  58. IOAddress() = default;
  59. explicit IOAddress(u16 address)
  60. : m_address(address)
  61. {
  62. }
  63. IOAddress offset(u16 o) const { return IOAddress(m_address + o); }
  64. u16 get() const { return m_address; }
  65. void set(u16 address) { m_address = address; }
  66. void mask(u16 m) { m_address &= m; }
  67. template<typename T>
  68. ALWAYS_INLINE T in()
  69. {
  70. static_assert(sizeof(T) <= 4);
  71. if constexpr (sizeof(T) == 4)
  72. return IO::in32(get());
  73. if constexpr (sizeof(T) == 2)
  74. return IO::in16(get());
  75. if constexpr (sizeof(T) == 1)
  76. return IO::in8(get());
  77. VERIFY_NOT_REACHED();
  78. }
  79. template<typename T>
  80. ALWAYS_INLINE void out(T value)
  81. {
  82. static_assert(sizeof(T) <= 4);
  83. if constexpr (sizeof(T) == 4) {
  84. IO::out32(get(), value);
  85. return;
  86. }
  87. if constexpr (sizeof(T) == 2) {
  88. IO::out16(get(), value);
  89. return;
  90. }
  91. if constexpr (sizeof(T) == 1) {
  92. IO::out8(get(), value);
  93. return;
  94. }
  95. VERIFY_NOT_REACHED();
  96. }
  97. inline void out(u32 value, u8 bit_width)
  98. {
  99. if (bit_width == 32) {
  100. IO::out32(get(), value);
  101. return;
  102. }
  103. if (bit_width == 16) {
  104. IO::out16(get(), value);
  105. return;
  106. }
  107. if (bit_width == 8) {
  108. IO::out8(get(), value);
  109. return;
  110. }
  111. VERIFY_NOT_REACHED();
  112. }
  113. bool is_null() const { return m_address == 0; }
  114. bool operator==(const IOAddress& other) const { return m_address == other.m_address; }
  115. bool operator!=(const IOAddress& other) const { return m_address != other.m_address; }
  116. bool operator>(const IOAddress& other) const { return m_address > other.m_address; }
  117. bool operator>=(const IOAddress& other) const { return m_address >= other.m_address; }
  118. bool operator<(const IOAddress& other) const { return m_address < other.m_address; }
  119. bool operator<=(const IOAddress& other) const { return m_address <= other.m_address; }
  120. private:
  121. u16 m_address { 0 };
  122. };
  123. template<>
  124. struct AK::Formatter<IOAddress> : AK::Formatter<FormatString> {
  125. void format(FormatBuilder& builder, IOAddress value)
  126. {
  127. return Formatter<FormatString>::format(builder, "IO {:x}", value.get());
  128. }
  129. };