diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2023-10-11 20:16:27 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2023-10-11 20:16:27 +0200 |
| commit | 18863e0f3db23441c0213745ad6de3722fd4c845 (patch) | |
| tree | 72aa8c7616738ef82a9251c8c6e56d48704eccb9 /source/arch/x86_64 | |
| parent | 25a02ae2b532f0afd846c9a3471a95ce222fb99e (diff) | |
| download | teachos-18863e0f3db23441c0213745ad6de3722fd4c845.tar.xz teachos-18863e0f3db23441c0213745ad6de3722fd4c845.zip | |
x86_64: io: implement simple port I/O operations
Diffstat (limited to 'source/arch/x86_64')
| -rw-r--r-- | source/arch/x86_64/include/arch/io/port_io.hpp | 131 |
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 |
