diff options
Diffstat (limited to 'arch/x86_64/include')
| -rw-r--r-- | arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp | 196 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/cpu/registers.hpp | 68 |
2 files changed, 197 insertions, 67 deletions
diff --git a/arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp b/arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp new file mode 100644 index 0000000..d892360 --- /dev/null +++ b/arch/x86_64/include/x86_64/cpu/impl/control_registers.hpp @@ -0,0 +1,196 @@ +#ifndef TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP +#define TEACHOS_X86_64_CPU_IMPL_CONTROL_REGISTERS_HPP + +#include "kapi/memory/address.hpp" + +#include <cstdint> +#include <string_view> +#include <type_traits> + +namespace teachos::cpu::x86_64 +{ + + namespace impl + { + constexpr auto static cr0_asm = std::pair<std::string_view, std::string_view>{"mov %%cr0, %0", "mov %0, %%cr0"}; + constexpr auto static cr2_asm = std::pair<std::string_view, std::string_view>{"mov %%cr2, %0", "mov %0, %%cr2"}; + constexpr auto static cr3_asm = std::pair<std::string_view, std::string_view>{"mov %%cr3, %0", "mov %0, %%cr3"}; + + template<typename Derived, typename ValueType, typename = void> + struct control_register_with_flags + { + }; + + template<typename Derived, typename ValueType> + struct control_register_with_flags<Derived, ValueType, std::enable_if_t<std::is_enum_v<ValueType>>> + { + using flags = ValueType; + + auto static set(ValueType value) -> void + { + auto current = Derived::read(); + current |= value; + Derived::write(current); + } + + auto static clear(ValueType value) -> void + { + auto current = Derived::read(); + current &= ~value; + Derived::write(current); + } + }; + + template<typename ValueType, auto AssemblerTemplates> + struct control_register : control_register_with_flags<control_register<ValueType, AssemblerTemplates>, ValueType> + { + [[nodiscard]] auto static read() -> ValueType + { + auto value = ValueType{}; + asm volatile((AssemblerTemplates->first) : "=r"(value)); + return value; + } + + auto static write(ValueType value) -> void + { + asm volatile((AssemblerTemplates->second) : : "r"(value)); + } + }; + + enum struct cr0_flags : uint64_t + { + //! Enable protected mode. + protection_enable = 1uz << 0, + //! Enable wait-monitoring of the coprocessor after task switching. + monitor_coprocessor = 1uz << 1, + //! Emulate floating point coprocessor. + emulation = 1uz << 2, + //! Marks that a task switch has occurred. + task_switched = 1uz << 3, + //! Marks Intel 387 DX math coprocessor as available + extension_type = 1uz << 4, + //! Numeric error handling mode. + numeric_error = 1uz << 5, + //! Disable writing to read-only marked memory. + write_protect = 1uz << 16, + //! Enable Ring-3 alignment checks + alignment_check = 1uz << 18, + //! Disable write through + not_write_through = 1uz << 29, + //! Disable caching of memory accesses + cache_disable = 1uz << 30, + //! Enable paging + paging = 1uz << 31 + }; + + constexpr auto operator|(cr0_flags lhs, cr0_flags rhs) -> cr0_flags + { + return static_cast<cr0_flags>(static_cast<std::underlying_type_t<cr0_flags>>(lhs) | + static_cast<std::underlying_type_t<cr0_flags>>(rhs)); + } + + constexpr auto operator|=(cr0_flags & lhs, cr0_flags rhs) -> cr0_flags & + { + lhs = lhs | rhs; + return lhs; + } + + constexpr auto operator&(cr0_flags lhs, cr0_flags rhs) -> cr0_flags + { + return static_cast<cr0_flags>(static_cast<std::underlying_type_t<cr0_flags>>(lhs) & + static_cast<std::underlying_type_t<cr0_flags>>(rhs)); + } + + constexpr auto operator&=(cr0_flags & lhs, cr0_flags rhs) -> cr0_flags & + { + lhs = lhs & rhs; + return lhs; + } + + constexpr auto operator~(cr0_flags lhs) -> cr0_flags + { + // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) + return static_cast<cr0_flags>(~static_cast<std::underlying_type_t<cr0_flags>>(lhs)); + } + + enum struct cr3_flags : std::uint64_t + { + page_level_write_through = 1uz << 0, + page_level_cache_disable = 1uz << 1, + }; + + constexpr auto operator|(cr3_flags lhs, cr3_flags rhs) -> cr3_flags + { + return static_cast<cr3_flags>(static_cast<std::underlying_type_t<cr3_flags>>(lhs) | + static_cast<std::underlying_type_t<cr3_flags>>(rhs)); + } + + constexpr auto operator|=(cr3_flags & lhs, cr3_flags rhs) -> cr3_flags & + { + lhs = lhs | rhs; + return lhs; + } + + constexpr auto operator&(cr3_flags lhs, cr3_flags rhs) -> cr3_flags + { + return static_cast<cr3_flags>(static_cast<std::underlying_type_t<cr3_flags>>(lhs) & + static_cast<std::underlying_type_t<cr3_flags>>(rhs)); + } + + constexpr auto operator&=(cr3_flags & lhs, cr3_flags rhs) -> cr3_flags & + { + lhs = lhs & rhs; + return lhs; + } + + constexpr auto operator~(cr3_flags lhs) -> cr3_flags + { + // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) + return static_cast<cr3_flags>(~static_cast<std::underlying_type_t<cr3_flags>>(lhs)); + } + + struct cr3_value + { + constexpr cr3_value() = default; + + constexpr cr3_value(memory::physical_address address, cr3_flags flags = static_cast<cr3_flags>(0)) + : m_flags{static_cast<std::uint64_t>(flags)} + , m_address{static_cast<std::uint64_t>(address.raw())} + {} + + [[nodiscard]] constexpr auto address() const -> memory::physical_address + { + return memory::physical_address{m_address}; + } + + constexpr auto address(memory::physical_address address) -> void + { + m_address = static_cast<std::uint64_t>(address.raw()); + } + + [[nodiscard]] constexpr auto flags() const -> cr3_flags + { + return static_cast<cr3_flags>(m_flags); + } + + constexpr auto flags(cr3_flags flags) -> void + { + m_flags = static_cast<std::uint64_t>(flags); + } + + private: + std::uint64_t : 3; + std::uint64_t m_flags : 2 {}; + std::uint64_t : 7; + std::uint64_t m_address : 52 {}; + }; + + } // namespace impl + + using cr0 = impl::control_register<impl::cr0_flags, &impl::cr0_asm>; + using cr2 = impl::control_register<memory::linear_address, &impl::cr2_asm>; + using cr3 = impl::control_register<impl::cr3_value, &impl::cr3_asm>; + +} // namespace teachos::cpu::x86_64 + +#endif
\ No newline at end of file diff --git a/arch/x86_64/include/x86_64/cpu/registers.hpp b/arch/x86_64/include/x86_64/cpu/registers.hpp index d19acfc..7f71b95 100644 --- a/arch/x86_64/include/x86_64/cpu/registers.hpp +++ b/arch/x86_64/include/x86_64/cpu/registers.hpp @@ -1,72 +1,6 @@ #ifndef TEACHOS_X86_64_CPU_REGISTERS_HPP #define TEACHOS_X86_64_CPU_REGISTERS_HPP -#include <cstdint> - -namespace teachos::cpu::x86_64 -{ - - /** - * @brief Control registers that can be read and written to. - * - * @note CR1 and CR5 - 7 are reserved and will throw an exception if they are accessed, therefore they are not defined - * in the enum. See https://en.wikipedia.org/wiki/Control_register#Control_registers_in_Intel_x86_series for more - * information. - */ - enum struct control_register : uint8_t - { - cr0, ///< Contains various control flags that modify basic operation of the processor, Machine Status World (MSW) - ///< register. - cr2 = 2U, ///< Contains Page Fault Linear Address (PFLA), when page fault occurs address program attended to accces - ///< is stored here. - cr3, ///< Enables process to translate linear addresses into physical addresses using paging, CR0 bit 32 Paging - ///< (PG) needs to be enabled simply contains the register value that represents the physical address of the - ///< level 4 page table used for paging in the system. Therefore reading this value allows to access the level - ///< 4 page table directly. Instead of over the virtual address 0xffffffff'fffff000, which then has to be - ///< first translated into a physical address. - cr4 ///< Used in protected mode to control operations. - }; - - /** - * @brief Control register 0 flags that can be set. - * - * @note Modifies the basic operation of the processor. Only the most important extensions are listed below, the rest - * are excluded for brevity. See https://en.wikipedia.org/wiki/Control_register#CR0 for more information. - */ - enum struct cr0_flags : uint64_t - { - PROTECTED_MODE_ENABLED = 1U << 0U, ///< System is in protected or system is in real mode. - TASK_SWITCHED = 1U << 3U, ///< Allows saving x87 task context upon a task switch only after x87 instruction used. - WRITE_PROTECT = 1U << 16U, ///< When set, the CPU cannot write to read-only pages when privilege level is 0. - PAGING = 1U << 31U, // Enable paging using the CR3 register. - }; - - /** - * @brief Reads the value of the given control register. - * - * @param cr Control register that should be read. - * @return Value of the control register. - */ - auto read_control_register(control_register cr) -> uint64_t; - - /** - * @brief Sets a specific bit in the Extended Feature Enable Register (EFER) Model-Specific Register (MSR) register. - * - * @param cr Control register that should be written. - * @param new_value New value that should be written. - */ - auto write_control_register(control_register cr, uint64_t new_value) -> void; - - /** - * @brief Sets a specific bit in the CR0. - * - * @note This function reads the current value of the CR0 register, ORs the specified - * bit with the current value, and writes the updated value back to the CR0. - * - * @param flag he flag to set in the CR0. - */ - auto set_cr0_bit(cr0_flags flag) -> void; - -} // namespace teachos::cpu::x86_64 +#include "x86_64/cpu/impl/control_registers.hpp" // IWYU pragma: export #endif
\ No newline at end of file |
