aboutsummaryrefslogtreecommitdiff
path: root/source/arch/x86_64/include
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2023-10-11 20:16:27 +0200
committerFelix Morgner <felix.morgner@ost.ch>2023-10-11 20:16:27 +0200
commit18863e0f3db23441c0213745ad6de3722fd4c845 (patch)
tree72aa8c7616738ef82a9251c8c6e56d48704eccb9 /source/arch/x86_64/include
parent25a02ae2b532f0afd846c9a3471a95ce222fb99e (diff)
downloadteachos-18863e0f3db23441c0213745ad6de3722fd4c845.tar.xz
teachos-18863e0f3db23441c0213745ad6de3722fd4c845.zip
x86_64: io: implement simple port I/O operations
Diffstat (limited to 'source/arch/x86_64/include')
-rw-r--r--source/arch/x86_64/include/arch/io/port_io.hpp131
1 files changed, 131 insertions, 0 deletions
diff --git a/source/arch/x86_64/include/arch/io/port_io.hpp b/source/arch/x86_64/include/arch/io/port_io.hpp
new file mode 100644
index 0000000..736893c
--- /dev/null
+++ b/source/arch/x86_64/include/arch/io/port_io.hpp
@@ -0,0 +1,131 @@
+#ifndef TEACHOS_ARCH_X86_64_IO_PORT_IO_HPP
+#define TEACHOS_ARCH_X86_64_IO_PORT_IO_HPP
+
+#include <concepts>
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+
+namespace teachos::arch::io
+{
+
+ /**
+ * @brief An I/O port of a given size at a given address.
+ *
+ * @tparam Address The address (port number) of the I/O port.
+ * @tparam Size The size (in bytes) of the I/O port.
+ */
+ template<std::uint16_t Address, std::size_t Size>
+ struct port
+ {
+ static_assert(Size == 1 || Size == 2 || Size == 4, "A port must be either 1, 2, or 4 bytes in size");
+
+ using io_type =
+ std::conditional_t<Size == 1, std::byte, std::conditional_t<Size == 2, std::uint16_t, std::uint32_t>>;
+
+ /**
+ * @brief Write a byte to the I/O port.
+ *
+ * @param data The data to write to the I/O port.
+ */
+ auto static write(io_type data) -> void
+ requires(Size == 1)
+ {
+ asm volatile("mov %[port], %%dx\n"
+ "mov %[data], %%al\n"
+ "out %%al, %%dx\n"
+ :
+ : [port] "i"(Address), [data] "im"(data)
+ : "dx", "al");
+ }
+
+ /**
+ * @brief Write a word to the I/O port.
+ *
+ * @param data The data to write to the I/O port.
+ */
+ auto static write(io_type data) -> void
+ requires(Size == 2)
+ {
+ asm volatile("mov %[port], %%dx\n"
+ "mov %[data], %%ax\n"
+ "out %%ax, %%dx\n"
+ :
+ : [port] "i"(Address), [data] "im"(data)
+ : "dx", "ax");
+ }
+
+ /**
+ * @brief Write a double-word to the I/O port.
+ *
+ * @param data The data to write to the I/O port.
+ */
+ auto static write(io_type data) -> void
+ requires(Size == 4)
+ {
+ asm volatile("mov %[port], %%dx\n"
+ "mov %[data], %%eax\n"
+ "out %%eax, %%dx\n"
+ :
+ : [port] "i"(Address), [data] "im"(data)
+ : "dx", "eax");
+ }
+
+ /**
+ * @brief Read a byte from the I/O port.
+ *
+ * @return The data read from the I/O port.
+ */
+ auto static read() -> io_type
+ requires(Size == 1)
+ {
+ auto data = io_type{};
+ asm volatile("mov %[port], %%dx\n"
+ "in %%dx, %%al\n"
+ "mov %%al, %[data]\n"
+ : [data] "=m"(data)
+ : [port] "i"(Address)
+ : "dx", "al");
+ return data;
+ }
+
+ /**
+ * @brief Read a word from the I/O port.
+ *
+ * @return The data read from the I/O port.
+ */
+ auto static read() -> io_type
+ requires(Size == 2)
+ {
+ auto data = io_type{};
+ asm volatile("mov %[port], %%dx\n"
+ "in %%dx, %%ax\n"
+ "mov %%ax, %[data]\n"
+ : [data] "=m"(data)
+ : [port] "i"(Address)
+ : "dx", "ax");
+ return data;
+ }
+
+ /**
+ * @brief Read a double-word from the I/O port.
+ *
+ * @return The data read from the I/O port.
+ */
+ auto static read() -> io_type
+ requires(Size == 4)
+ {
+ auto data = io_type{};
+ asm volatile("mov %[port], %%dx\n"
+ "in %%dx, %%eax\n"
+ "mov %%eax, %[data]\n"
+ : [data] "=m"(data)
+ : [port] "i"(Address)
+ : "dx", "eax");
+ return data;
+ }
+ };
+
+} // namespace teachos::arch::io
+
+#endif \ No newline at end of file