aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.vscode/settings.json5
-rw-r--r--arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp112
-rw-r--r--arch/x86_64/include/x86_64/cpu/registers.hpp3
-rw-r--r--arch/x86_64/src/kapi/memory.cpp3
4 files changed, 119 insertions, 4 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 8cee879..dcf1d1a 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -23,11 +23,14 @@
},
"cSpell.words": [
"crtc",
+ "efer",
"invlpg",
"kapi",
"kstd",
"NOLINTNEXTLINE",
+ "rdmsr",
"rvalues",
- "TeachOS"
+ "TeachOS",
+ "wrmsr"
]
} \ No newline at end of file
diff --git a/arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp b/arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp
new file mode 100644
index 0000000..8a41a8a
--- /dev/null
+++ b/arch/x86_64/include/x86_64/cpu/impl/model_specific_register.hpp
@@ -0,0 +1,112 @@
+#ifndef TEACHOS_X86_64_CPU_IMPL_MODEL_SPECIFIC_REGISTER_HPP
+#define TEACHOS_X86_64_CPU_IMPL_MODEL_SPECIFIC_REGISTER_HPP
+
+#include <bit>
+#include <cstdint>
+#include <type_traits>
+
+namespace teachos::cpu::x86_64
+{
+ namespace impl
+ {
+ constexpr auto ia32_efer_number = 0xC000'0080u;
+
+ template<typename Derived, typename ValueType, typename = void>
+ struct model_specific_register_with_flags
+ {
+ };
+
+ template<typename Derived, typename ValueType>
+ struct model_specific_register_with_flags<Derived, ValueType, std::enable_if_t<std::is_enum_v<ValueType>>>
+ {
+ using flags = ValueType;
+
+ auto static set(flags flag) -> void
+ {
+ auto current = Derived::read();
+ current |= flag;
+ Derived::write(current);
+ }
+
+ auto static clear(flags flag) -> void
+ {
+ auto current = Derived::read();
+ current &= ~flag;
+ Derived::write(current);
+ }
+
+ auto test(flags flag) -> void
+ {
+ return Derived::read() & flag;
+ }
+ };
+
+ template<std::uint32_t Number, typename ValueType>
+ struct model_specific_register
+ : model_specific_register_with_flags<model_specific_register<Number, ValueType>, ValueType>
+ {
+ struct raw_value
+ {
+ std::uint32_t low_half;
+ std::uint32_t high_half;
+ };
+
+ auto static read() -> ValueType
+ {
+ auto raw = raw_value{};
+ asm volatile("rdmsr" : "=a"(raw.low_half), "=d"(raw.high_half) : "c"(Number));
+ return static_cast<ValueType>(std::bit_cast<std::uint64_t>(raw));
+ }
+
+ auto static write(ValueType value) -> void
+ {
+ auto raw = std::bit_cast<raw_value>(static_cast<std::uint64_t>(value));
+ asm volatile("wrmsr" : : "a"(raw.low_half), "d"(raw.high_half), "c"(Number));
+ }
+ };
+
+ enum struct ia32_efer_flags : std::uint64_t
+ {
+ syscall_enable = 1uz << 0,
+ ia32e_mode_enable = 1uz << 8,
+ ia32e_mode_active = 1uz << 10,
+ execute_disable_bit_enable = 1uz << 11,
+ };
+
+ constexpr auto operator|(ia32_efer_flags lhs, ia32_efer_flags rhs) -> ia32_efer_flags
+ {
+ return static_cast<ia32_efer_flags>(static_cast<std::underlying_type_t<ia32_efer_flags>>(lhs) |
+ static_cast<std::underlying_type_t<ia32_efer_flags>>(rhs));
+ }
+
+ constexpr auto operator|=(ia32_efer_flags & lhs, ia32_efer_flags rhs) -> ia32_efer_flags &
+ {
+ lhs = lhs | rhs;
+ return lhs;
+ }
+
+ constexpr auto operator&(ia32_efer_flags lhs, ia32_efer_flags rhs) -> ia32_efer_flags
+ {
+ return static_cast<ia32_efer_flags>(static_cast<std::underlying_type_t<ia32_efer_flags>>(lhs) &
+ static_cast<std::underlying_type_t<ia32_efer_flags>>(rhs));
+ }
+
+ constexpr auto operator&=(ia32_efer_flags & lhs, ia32_efer_flags rhs) -> ia32_efer_flags &
+ {
+ lhs = lhs & rhs;
+ return lhs;
+ }
+
+ constexpr auto operator~(ia32_efer_flags lhs) -> ia32_efer_flags
+ {
+ // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
+ return static_cast<ia32_efer_flags>(~static_cast<std::underlying_type_t<ia32_efer_flags>>(lhs));
+ }
+
+ } // namespace impl
+
+ using i32_efer = impl::model_specific_register<impl::ia32_efer_number, impl::ia32_efer_flags>;
+
+} // 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 7f71b95..97cba19 100644
--- a/arch/x86_64/include/x86_64/cpu/registers.hpp
+++ b/arch/x86_64/include/x86_64/cpu/registers.hpp
@@ -1,6 +1,7 @@
#ifndef TEACHOS_X86_64_CPU_REGISTERS_HPP
#define TEACHOS_X86_64_CPU_REGISTERS_HPP
-#include "x86_64/cpu/impl/control_registers.hpp" // IWYU pragma: export
+#include "x86_64/cpu/impl/control_registers.hpp" // IWYU pragma: export
+#include "x86_64/cpu/impl/model_specific_register.hpp" // IWYU pragma: export
#endif \ No newline at end of file
diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp
index 6102bee..d0d966b 100644
--- a/arch/x86_64/src/kapi/memory.cpp
+++ b/arch/x86_64/src/kapi/memory.cpp
@@ -6,7 +6,6 @@
#include "x86_64/boot/boot.hpp"
#include "x86_64/boot/ld.hpp"
-#include "x86_64/cpu/impl/control_registers.hpp"
#include "x86_64/cpu/registers.hpp"
#include "x86_64/memory/region_allocator.hpp"
@@ -50,7 +49,7 @@ namespace teachos::memory
auto enable_cpu_protections() -> void
{
cpu::x86_64::cr0::set(cpu::x86_64::cr0::flags::write_protect);
- // set_efer_bit(efer_flags::NXE);
+ cpu::x86_64::i32_efer::set(cpu::x86_64::i32_efer::flags::execute_disable_bit_enable);
}
} // namespace