From 2e4cbd473ff3bb7ac7371af39becf830b4fb753b Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 13 Mar 2025 14:05:45 +0000 Subject: IN_PROGRESS implement gdt initialization --- arch/x86_64/CMakeLists.txt | 12 ++-- .../descriptor_table/global_descriptor_table.hpp | 19 ++++++ .../global_descriptor_table_pointer.hpp | 23 +++++++ .../include/arch/kernel/cpu/control_register.hpp | 71 +++++++++++++++++++++ arch/x86_64/include/arch/kernel/cpu/msr.hpp | 64 +++++++++++++++++++ arch/x86_64/include/arch/kernel/cpu/ss.hpp | 56 +++++++++++++++++ arch/x86_64/include/arch/kernel/cpu/tlb.hpp | 27 ++++++++ .../include/arch/memory/cpu/control_register.hpp | 71 --------------------- arch/x86_64/include/arch/memory/cpu/msr.hpp | 64 ------------------- arch/x86_64/include/arch/memory/cpu/tlb.hpp | 27 -------- .../arch/memory/paging/active_page_table.hpp | 6 +- .../include/arch/memory/paging/kernel_mapper.hpp | 2 +- arch/x86_64/src/boot/boot.s | 2 +- .../descriptor_table/global_descriptor_table.cpp | 57 +++++++++++++++++ arch/x86_64/src/kernel/cpu/control_register.cpp | 72 ++++++++++++++++++++++ arch/x86_64/src/kernel/cpu/msr.cpp | 31 ++++++++++ arch/x86_64/src/kernel/cpu/ss.cpp | 33 ++++++++++ arch/x86_64/src/kernel/cpu/tlb.cpp | 16 +++++ arch/x86_64/src/kernel/main.cpp | 44 ++----------- arch/x86_64/src/memory/cpu/control_register.cpp | 72 ---------------------- arch/x86_64/src/memory/cpu/msr.cpp | 31 ---------- arch/x86_64/src/memory/cpu/tlb.cpp | 16 ----- arch/x86_64/src/memory/main.cpp | 4 +- 23 files changed, 487 insertions(+), 333 deletions(-) create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp create mode 100644 arch/x86_64/include/arch/kernel/cpu/control_register.hpp create mode 100644 arch/x86_64/include/arch/kernel/cpu/msr.hpp create mode 100644 arch/x86_64/include/arch/kernel/cpu/ss.hpp create mode 100644 arch/x86_64/include/arch/kernel/cpu/tlb.hpp delete mode 100644 arch/x86_64/include/arch/memory/cpu/control_register.hpp delete mode 100644 arch/x86_64/include/arch/memory/cpu/msr.hpp delete mode 100644 arch/x86_64/include/arch/memory/cpu/tlb.hpp create mode 100644 arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp create mode 100644 arch/x86_64/src/kernel/cpu/control_register.cpp create mode 100644 arch/x86_64/src/kernel/cpu/msr.cpp create mode 100644 arch/x86_64/src/kernel/cpu/ss.cpp create mode 100644 arch/x86_64/src/kernel/cpu/tlb.cpp delete mode 100644 arch/x86_64/src/memory/cpu/control_register.cpp delete mode 100644 arch/x86_64/src/memory/cpu/msr.cpp delete mode 100644 arch/x86_64/src/memory/cpu/tlb.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 1b8349a..9d59d87 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -7,6 +7,10 @@ mark_as_advanced(TEACHOS_KERNEL_LINKER_SCRIPT) target_sources("_kernel" PRIVATE "src/kernel/main.cpp" + "src/kernel/cpu/tlb.cpp" + "src/kernel/cpu/control_register.cpp" + "src/kernel/cpu/msr.cpp" + "src/kernel/cpu/ss.cpp" ) target_link_options("_kernel" PRIVATE @@ -53,9 +57,6 @@ target_sources("_memory" PRIVATE "src/memory/paging/virtual_page.cpp" "src/memory/paging/active_page_table.cpp" "src/memory/paging/inactive_page_table.cpp" - "src/memory/cpu/tlb.cpp" - "src/memory/cpu/control_register.cpp" - "src/memory/cpu/msr.cpp" "src/memory/heap/bump_allocator.cpp" "src/memory/heap/memory_block.cpp" "src/memory/heap/linked_list_allocator.cpp" @@ -86,10 +87,11 @@ target_sources("_exception" PRIVATE #]============================================================================] target_sources("_context" PRIVATE - "src/context_switching/descriptor_table/gdt_flags.cpp" "src/context_switching/descriptor_table/access_byte.cpp" - "src/context_switching/descriptor_table/type_field.cpp" + "src/context_switching/descriptor_table/gdt_flags.cpp" + "src/context_switching/descriptor_table/global_descriptor_table.cpp" "src/context_switching/descriptor_table/segment_descriptor.cpp" + "src/context_switching/descriptor_table/type_field.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp index e69de29..daba1fe 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table.hpp @@ -0,0 +1,19 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP + +#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" +#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" +#include "arch/stl/vector.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + typedef stl::vector global_descriptor_table; + + auto create_global_descriptor_table() -> global_descriptor_table; + + auto load_global_descriptor_table(global_descriptor_table_pointer gdt_pointer) -> void; + + auto initialize_global_descriptor_table() -> global_descriptor_table; +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp new file mode 100644 index 0000000..c2925fd --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp @@ -0,0 +1,23 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP + +#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" + +#include + +namespace teachos::arch::context_switching::descriptor_table +{ + /** + * @brief Represents a pointer to the Global Descriptor Table (GDT). + * + * This structure is used to store the base address and length of the GDT. + * It is used when loading or modifying the GDT during context switching. + */ + struct global_descriptor_table_pointer + { + uint16_t table_length; ///< The size of the GDT in bytes. + global_descriptor_table * address; ///< Pointer to the GDT base address. + }; +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/control_register.hpp b/arch/x86_64/include/arch/kernel/cpu/control_register.hpp new file mode 100644 index 0000000..27c7777 --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/control_register.hpp @@ -0,0 +1,71 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_CR3_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_CR3_HPP + +#include + +namespace teachos::arch::memory::cpu +{ + /** + * @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::arch::memory::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_CR3_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/msr.hpp b/arch/x86_64/include/arch/kernel/cpu/msr.hpp new file mode 100644 index 0000000..52d74bd --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/msr.hpp @@ -0,0 +1,64 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP + +#include +#include + +namespace teachos::arch::memory::cpu +{ + /** + * @brief Important flags that can be writen into the Extended Feature Enable Register (EFER). + * + * @note EFER is a model-specific register allowing to configure CPU extensions. Only the most important extensions + * are listed below, the rest are excluded for brevity. See https://en.wikipedia.org/wiki/Control_register#EFER for + * more information. + */ + enum class efer_flags : uint64_t + { + SCE = 1UL << 0UL, ///< System Call Extensions. + LME = 1UL << 8UL, ///< Long Mode Enabled. + LMA = 1UL << 10UL, ///< Long Mode Active. + NXE = 1UL << 11UL, ///< No-Execute Enable. + SVME = 1UL << 12UL, ///< Secure Virtual Machine Enable. + LMSLE = 1UL << 13UL, ///< Long Mode Segment Limit Enable. + FFXSR = 1UL << 14UL, ///< Fast FXSAVE/FXSTOR. + TCE = 1UL << 15UL, ///< Translation Cache Extension. + }; + + /** + * @brief Reads a 64-bit from the Model-Specific Register (MSR). + * + * @note This function reads the value of an MSR specified by the given address. It combines the lower and upper + * 32-bits of the MSR value read using the 'rdmsr' instruction and returns it as a 64-bit unsigned integer. + * + * @param msr The address of the MSR to read. + * @return The 64-bit value read from the MSR. + */ + auto read_msr(uint32_t msr) -> uint64_t; + + /** + * @brief Writes a 64-bit value to a Model-Specific Register (MSR). + * + * @note This function writes a 64-bit value to the MSR specified by the given address. + * It splits the 64-bit value into two 32-bit parts and writes them using the + * `wrmsr` instruction. + * + * @param msr The address of the MSR to write to. + * @param new_value The 64-bit value to write to the MSR. + */ + auto write_msr(uint32_t msr, uint64_t new_value) -> void; + + /** + * @brief Sets a specific bit in the Extended Feature Enable Register (EFER), which is a Model-Specific Register + * (MSR). + * + * @note This function reads the current value of the EFER register, ORs the specified + * bit with the current value, and writes the updated value back to the EFER register. + * + * @param flag The flag to set in the EFER register. + */ + auto set_efer_bit(efer_flags flag) -> void; + +} // namespace teachos::arch::memory::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/kernel/cpu/ss.hpp b/arch/x86_64/include/arch/kernel/cpu/ss.hpp new file mode 100644 index 0000000..2d3518e --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/ss.hpp @@ -0,0 +1,56 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_SS_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_SS_HPP + +#include +#include + +namespace teachos::arch::memory::cpu +{ + /** + * @brief Represents a segment selector in the x86_64 architecture. + * + * A segment selector is a 16-bit identifier used to select a segment descriptor + * from the Global Descriptor Table (GDT) or the Local Descriptor Table (LDT). + * It contains an index, a table indicator (TI), and a requested privilege level (RPL). + */ + struct segment_selector + { + /** + * @brief Constructs a segment selector. + * + * @param index The index of the segment descriptor. + * @param table_indicator The table indicator (0 for GDT, 1 for LDT). + * @param requested_privilege_level The requested privilege level (0-3). + */ + segment_selector(uint16_t index, std::bitset<1U> table_indicator, std::bitset<2U> requested_privilege_level); + + /** + * @brief Converts the segment selector to a 16-bit value. + * + * @return uint16_t The 16-bit representation of the segment selector. + */ + auto to_uint16() const -> uint16_t; + + private: + uint16_t index; + std::bitset<1U> table_indicator; + std::bitset<2U> requested_privilege_level; + }; + + /** + * @brief Reads the current value of the stack segment (SS) register. + * + * @return uint16_t The current SS register value. + */ + auto read_ss() -> uint16_t; + + /** + * @brief Writes a new value to the stack segment (SS) register. + * + * @param selector The segment selector to be written to SS. + */ + auto write_ss(segment_selector selector) -> void; + +} // namespace teachos::arch::memory::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_SS_HPP diff --git a/arch/x86_64/include/arch/kernel/cpu/tlb.hpp b/arch/x86_64/include/arch/kernel/cpu/tlb.hpp new file mode 100644 index 0000000..333cd58 --- /dev/null +++ b/arch/x86_64/include/arch/kernel/cpu/tlb.hpp @@ -0,0 +1,27 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_TLB_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_CPU_TLB_HPP + +#include "arch/memory/paging/virtual_page.hpp" + +namespace teachos::arch::memory::cpu +{ + /** + * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained + * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. + * + * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for + * that page. + */ + auto tlb_flush(paging::virtual_address address) -> void; + + /** + * @brief Invalidates the translation lookaside buffer (TLB) entry for all page tables. + * + * @note Simply reassigns the CR3 register the value of the CR3 register, causing a flush of the TLB buffer, because + * the system has to assume that the location of the level 4 page table moved. + */ + auto tlb_flush_all() -> void; + +} // namespace teachos::arch::memory::cpu + +#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_TLB_HPP diff --git a/arch/x86_64/include/arch/memory/cpu/control_register.hpp b/arch/x86_64/include/arch/memory/cpu/control_register.hpp deleted file mode 100644 index e11813d..0000000 --- a/arch/x86_64/include/arch/memory/cpu/control_register.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP - -#include - -namespace teachos::arch::memory::cpu -{ - /** - * @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::arch::memory::cpu - -#endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP diff --git a/arch/x86_64/include/arch/memory/cpu/msr.hpp b/arch/x86_64/include/arch/memory/cpu/msr.hpp deleted file mode 100644 index cda70e2..0000000 --- a/arch/x86_64/include/arch/memory/cpu/msr.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_CPU_NXE_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_CPU_NXE_HPP - -#include -#include - -namespace teachos::arch::memory::cpu -{ - /** - * @brief Important flags that can be writen into the Extended Feature Enable Register (EFER). - * - * @note EFER is a model-specific register allowing to configure CPU extensions. Only the most important extensions - * are listed below, the rest are excluded for brevity. See https://en.wikipedia.org/wiki/Control_register#EFER for - * more information. - */ - enum class efer_flags : uint64_t - { - SCE = 1UL << 0UL, ///< System Call Extensions. - LME = 1UL << 8UL, ///< Long Mode Enabled. - LMA = 1UL << 10UL, ///< Long Mode Active. - NXE = 1UL << 11UL, ///< No-Execute Enable. - SVME = 1UL << 12UL, ///< Secure Virtual Machine Enable. - LMSLE = 1UL << 13UL, ///< Long Mode Segment Limit Enable. - FFXSR = 1UL << 14UL, ///< Fast FXSAVE/FXSTOR. - TCE = 1UL << 15UL, ///< Translation Cache Extension. - }; - - /** - * @brief Reads a 64-bit from the Model-Specific Register (MSR). - * - * @note This function reads the value of an MSR specified by the given address. It combines the lower and upper - * 32-bits of the MSR value read using the 'rdmsr' instruction and returns it as a 64-bit unsigned integer. - * - * @param msr The address of the MSR to read. - * @return The 64-bit value read from the MSR. - */ - auto read_msr(uint32_t msr) -> uint64_t; - - /** - * @brief Writes a 64-bit value to a Model-Specific Register (MSR). - * - * @note This function writes a 64-bit value to the MSR specified by the given address. - * It splits the 64-bit value into two 32-bit parts and writes them using the - * `wrmsr` instruction. - * - * @param msr The address of the MSR to write to. - * @param new_value The 64-bit value to write to the MSR. - */ - auto write_msr(uint32_t msr, uint64_t new_value) -> void; - - /** - * @brief Sets a specific bit in the Extended Feature Enable Register (EFER), which is a Model-Specific Register - * (MSR). - * - * @note This function reads the current value of the EFER register, ORs the specified - * bit with the current value, and writes the updated value back to the EFER register. - * - * @param flag The flag to set in the EFER register. - */ - auto set_efer_bit(efer_flags flag) -> void; - -} // namespace teachos::arch::memory::cpu - -#endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_NXE_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/cpu/tlb.hpp b/arch/x86_64/include/arch/memory/cpu/tlb.hpp deleted file mode 100644 index 075d7bb..0000000 --- a/arch/x86_64/include/arch/memory/cpu/tlb.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_CPU_TLB_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_CPU_TLB_HPP - -#include "arch/memory/paging/virtual_page.hpp" - -namespace teachos::arch::memory::cpu -{ - /** - * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained - * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. - * - * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for - * that page. - */ - auto tlb_flush(paging::virtual_address address) -> void; - - /** - * @brief Invalidates the translation lookaside buffer (TLB) entry for all page tables. - * - * @note Simply reassigns the CR3 register the value of the CR3 register, causing a flush of the TLB buffer, because - * the system has to assume that the location of the level 4 page table moved. - */ - auto tlb_flush_all() -> void; - -} // namespace teachos::arch::memory::cpu - -#endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_TLB_HPP diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index 1b2aaed..9846a21 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -2,8 +2,8 @@ #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP #include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/tlb.hpp" #include "arch/memory/allocator/concept.hpp" -#include "arch/memory/cpu/tlb.hpp" #include "arch/memory/paging/virtual_page.hpp" #include @@ -75,8 +75,8 @@ namespace teachos::arch::memory::paging * @param flags A bitset of flags that configure the page table entry for this mapping. */ template - auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, - std::bitset<64U> flags) -> void + auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, std::bitset<64U> flags) + -> void { auto current_handle = active_handle; diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 74f1c14..b137736 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP -#include "arch/memory/cpu/control_register.hpp" +#include "arch/kernel/cpu/control_register.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/inactive_page_table.hpp" #include "arch/memory/paging/temporary_page.hpp" diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index dbea42a..39bfe33 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -199,7 +199,7 @@ _start: cli /* Clears the interrupt flag during the GDT setup */ lgdt (global_descriptor_table_pointer) - jmp $global_descriptor_table_code,$_transition_to_long_mode + jmp $global_descriptor_table_code, $_transition_to_long_mode /* The interrupt flag is set in cpp after setting up the GDT */ call halt diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp new file mode 100644 index 0000000..1cba13c --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp @@ -0,0 +1,57 @@ +#include "global_descriptor_table.hpp" + +#include "arch/stl/vector.hpp" + +#include "segment_descriptor.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + auto create_global_descriptor_table() -> global_descriptor_table + { + segment_descriptor null_segment{0}; + + // Kernel space code segment + access_byte kernel_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | + access_byte::CODE_OR_DATA_SEGMENT, + type_field::CODE_SEGMENT | type_field::READABLE}; + gdt_flags kernel_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH}; + segment_descriptor kernel_code_segment{kernel_code_access_byte, kernel_code_gdt_flags, 0, 0xFFFFF}; + + // Kernel space data segment + access_byte kernel_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | + access_byte::CODE_OR_DATA_SEGMENT, + type_field::WRITABLE}; + gdt_flags kernel_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND}; + segment_descriptor kernel_data_segment{kernel_data_access_byte, kernel_data_gdt_flags, 0, 0xFFFFF}; + + // User space code segment + access_byte user_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | + access_byte::CODE_OR_DATA_SEGMENT, + type_field::CODE_SEGMENT | type_field::READABLE}; + gdt_flags user_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH}; + segment_descriptor user_code_segment{user_code_access_byte, user_code_gdt_flags, 0, 0xFFFFF}; + + // User space data segment + access_byte user_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | + access_byte::CODE_OR_DATA_SEGMENT, + type_field::WRITABLE}; + gdt_flags user_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND}; + segment_descriptor user_data_segment{user_data_access_byte, user_data_gdt_flags, 0, 0xFFFFF}; + + stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment}; + return global_descriptor_table; + } + + auto load_global_descriptor_table(global_descriptor_table_pointer gdt_pointer) -> void + { + // + } + + auto initialize_global_descriptor_table() -> global_descriptor_table + { + global_descriptor_table gdt{create_global_descriptor_table()}; + global_descriptor_table_pointer gdt_pointer{gdt.size() - 1, &gdt}; + load_global_descriptor_table(gdt_pointer); + } +} // namespace teachos::arch::context_switching::descriptor_table \ No newline at end of file diff --git a/arch/x86_64/src/kernel/cpu/control_register.cpp b/arch/x86_64/src/kernel/cpu/control_register.cpp new file mode 100644 index 0000000..3051bae --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/control_register.cpp @@ -0,0 +1,72 @@ +#include "arch/kernel/cpu/control_register.hpp" + +#include "arch/exception_handling/panic.hpp" + +#include + +namespace teachos::arch::memory::cpu +{ + auto read_control_register(control_register cr) -> uint64_t + { + uint64_t current_value; + switch (cr) + { + case control_register::CR0: + asm volatile("mov %%cr0, %[output]" : [output] "=r"(current_value)); + break; + case control_register::CR2: + asm volatile("mov %%cr2, %[output]" : [output] "=r"(current_value)); + break; + case control_register::CR3: + asm volatile("mov %%cr3, %[output]" : [output] "=r"(current_value)); + break; + case control_register::CR4: + asm volatile("mov %%cr4, %[output]" : [output] "=r"(current_value)); + break; + default: + exception_handling::panic("[Control Register] Attempted to read non-existent or reserved control register"); + break; + } + return current_value; + } + + auto write_control_register(control_register cr, uint64_t new_value) -> void + { + switch (cr) + { + case control_register::CR0: + asm volatile("mov %[input], %%cr0" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + case control_register::CR2: + asm volatile("mov %[input], %%cr2" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + case control_register::CR3: + asm volatile("mov %[input], %%cr3" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + case control_register::CR4: + asm volatile("mov %[input], %%cr4" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + default: + exception_handling::panic("[Control Register] Attempted to write non-existent or reserved control register"); + break; + } + } + + auto set_cr0_bit(cr0_flags flag) -> void + { + auto const cr0 = read_control_register(control_register::CR0); + write_control_register(control_register::CR0, static_cast::type>(flag) | cr0); + } +} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/kernel/cpu/msr.cpp b/arch/x86_64/src/kernel/cpu/msr.cpp new file mode 100644 index 0000000..082bca9 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/msr.cpp @@ -0,0 +1,31 @@ +#include "arch/kernel/cpu/msr.hpp" + +namespace teachos::arch::memory::cpu +{ + namespace + { + auto constexpr IA32_EFER_ADDRESS = 0xC0000080; + } + + auto read_msr(uint32_t msr) -> uint64_t + { + uint32_t low, high; + asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr)); + return (static_cast(high) << 32) | low; + } + + auto write_msr(uint32_t msr, uint64_t value) -> void + { + uint32_t low = value & 0xFFFFFFFF; + uint32_t high = value >> 32; + asm volatile("wrmsr" + : /* no output from call */ + : "c"(msr), "a"(low), "d"(high)); + } + + auto set_efer_bit(efer_flags flag) -> void + { + auto const efer = read_msr(IA32_EFER_ADDRESS); + write_msr(IA32_EFER_ADDRESS, static_cast::type>(flag) | efer); + } +} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/kernel/cpu/ss.cpp b/arch/x86_64/src/kernel/cpu/ss.cpp new file mode 100644 index 0000000..b7e52e1 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/ss.cpp @@ -0,0 +1,33 @@ +#include "arch/kernel/cpu/ss.hpp" + +namespace teachos::arch::memory::cpu +{ + segment_selector::segment_selector(uint16_t index, std::bitset<1U> table_indicator, + std::bitset<2U> requested_privilege_level) + : index(index) + , table_indicator(table_indicator) + , requested_privilege_level(requested_privilege_level) + { + // Nothing to do + } + + auto segment_selector::to_uint16() const -> uint16_t + { + return static_cast((index << 3) | (table_indicator.to_ulong() << 2) | + requested_privilege_level.to_ulong()); + } + + auto read_ss() -> uint16_t + { + uint16_t ss; + __asm__("mov %%ss, %0" : "=r"(ss)); + return ss; + } + + auto write_ss(segment_selector selector) -> void + { + uint16_t ss = selector.to_uint16(); + __asm__("mov %0, %%ss" ::"r"(ss)); + } + +} // namespace teachos::arch::memory::cpu \ No newline at end of file diff --git a/arch/x86_64/src/kernel/cpu/tlb.cpp b/arch/x86_64/src/kernel/cpu/tlb.cpp new file mode 100644 index 0000000..e753c2c --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/tlb.cpp @@ -0,0 +1,16 @@ +#include "arch/kernel/cpu/tlb.hpp" + +#include "arch/kernel/cpu/control_register.hpp" + +namespace teachos::arch::memory::cpu +{ + auto tlb_flush(paging::virtual_address address) -> void + { + asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); + } + + auto tlb_flush_all() -> void + { + write_control_register(cpu::control_register::CR3, read_control_register(cpu::control_register::CR3)); + } +} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index d3938ed..4db9599 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,6 +1,6 @@ #include "arch/kernel/main.hpp" -#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" +#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/main.hpp" @@ -60,50 +60,14 @@ namespace teachos::arch::kernel heap_test(); - using context_switching::descriptor_table::access_byte; - using context_switching::descriptor_table::gdt_flags; - using context_switching::descriptor_table::segment_descriptor; - using context_switching::descriptor_table::segment_descriptor_type; - using context_switching::descriptor_table::type_field; - - segment_descriptor null_segment{0}; - - // Kernel space code segment - access_byte kernel_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | - access_byte::CODE_OR_DATA_SEGMENT, - type_field::CODE_SEGMENT | type_field::READABLE}; - gdt_flags kernel_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH}; - segment_descriptor kernel_code_segment{kernel_code_access_byte, kernel_code_gdt_flags, 0, 0xFFFFF}; - - // Kernel space data segment - access_byte kernel_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | - access_byte::CODE_OR_DATA_SEGMENT, - type_field::WRITABLE}; - gdt_flags kernel_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND}; - segment_descriptor kernel_data_segment{kernel_data_access_byte, kernel_data_gdt_flags, 0, 0xFFFFF}; - - // User space code segment - access_byte user_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | - access_byte::CODE_OR_DATA_SEGMENT, - type_field::CODE_SEGMENT | type_field::READABLE}; - gdt_flags user_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH}; - segment_descriptor user_code_segment{user_code_access_byte, user_code_gdt_flags, 0, 0xFFFFF}; - - // User space data segment - access_byte user_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | - access_byte::CODE_OR_DATA_SEGMENT, - type_field::WRITABLE}; - gdt_flags user_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND}; - segment_descriptor user_data_segment{user_data_access_byte, user_data_gdt_flags, 0, 0xFFFFF}; - - stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment}; + context_switching::descriptor_table::global_descriptor_table global_descriptor_table{ + context_switching::descriptor_table::initialize_global_descriptor_table()}; decltype(auto) x = global_descriptor_table.at(1); if (global_descriptor_table.size() == 0) { } - if (x.get_segment_type() == segment_descriptor_type::CODE_SEGMENT) + if (x.get_segment_type() == context_switching::descriptor_table::segment_descriptor_type::CODE_SEGMENT) { } video::vga::text::write("GDT FILLED", video::vga::text::common_attributes::green_on_black); diff --git a/arch/x86_64/src/memory/cpu/control_register.cpp b/arch/x86_64/src/memory/cpu/control_register.cpp deleted file mode 100644 index 7ee88b5..0000000 --- a/arch/x86_64/src/memory/cpu/control_register.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "arch/memory/cpu/control_register.hpp" - -#include "arch/exception_handling/panic.hpp" - -#include - -namespace teachos::arch::memory::cpu -{ - auto read_control_register(control_register cr) -> uint64_t - { - uint64_t current_value; - switch (cr) - { - case control_register::CR0: - asm volatile("mov %%cr0, %[output]" : [output] "=r"(current_value)); - break; - case control_register::CR2: - asm volatile("mov %%cr2, %[output]" : [output] "=r"(current_value)); - break; - case control_register::CR3: - asm volatile("mov %%cr3, %[output]" : [output] "=r"(current_value)); - break; - case control_register::CR4: - asm volatile("mov %%cr4, %[output]" : [output] "=r"(current_value)); - break; - default: - exception_handling::panic("[Control Register] Attempted to read non-existent or reserved control register"); - break; - } - return current_value; - } - - auto write_control_register(control_register cr, uint64_t new_value) -> void - { - switch (cr) - { - case control_register::CR0: - asm volatile("mov %[input], %%cr0" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::CR2: - asm volatile("mov %[input], %%cr2" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::CR3: - asm volatile("mov %[input], %%cr3" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::CR4: - asm volatile("mov %[input], %%cr4" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - default: - exception_handling::panic("[Control Register] Attempted to write non-existent or reserved control register"); - break; - } - } - - auto set_cr0_bit(cr0_flags flag) -> void - { - auto const cr0 = read_control_register(control_register::CR0); - write_control_register(control_register::CR0, static_cast::type>(flag) | cr0); - } -} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/cpu/msr.cpp b/arch/x86_64/src/memory/cpu/msr.cpp deleted file mode 100644 index b83f902..0000000 --- a/arch/x86_64/src/memory/cpu/msr.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "arch/memory/cpu/msr.hpp" - -namespace teachos::arch::memory::cpu -{ - namespace - { - auto constexpr IA32_EFER_ADDRESS = 0xC0000080; - } - - auto read_msr(uint32_t msr) -> uint64_t - { - uint32_t low, high; - asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr)); - return (static_cast(high) << 32) | low; - } - - auto write_msr(uint32_t msr, uint64_t value) -> void - { - uint32_t low = value & 0xFFFFFFFF; - uint32_t high = value >> 32; - asm volatile("wrmsr" - : /* no output from call */ - : "c"(msr), "a"(low), "d"(high)); - } - - auto set_efer_bit(efer_flags flag) -> void - { - auto const efer = read_msr(IA32_EFER_ADDRESS); - write_msr(IA32_EFER_ADDRESS, static_cast::type>(flag) | efer); - } -} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/cpu/tlb.cpp b/arch/x86_64/src/memory/cpu/tlb.cpp deleted file mode 100644 index 591d9fc..0000000 --- a/arch/x86_64/src/memory/cpu/tlb.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "arch/memory/cpu/tlb.hpp" - -#include "arch/memory/cpu/control_register.hpp" - -namespace teachos::arch::memory::cpu -{ - auto tlb_flush(paging::virtual_address address) -> void - { - asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); - } - - auto tlb_flush_all() -> void - { - write_control_register(cpu::control_register::CR3, read_control_register(cpu::control_register::CR3)); - } -} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index a6f91d9..abc7431 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -1,9 +1,9 @@ #include "arch/memory/main.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/control_register.hpp" +#include "arch/kernel/cpu/msr.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" -#include "arch/memory/cpu/control_register.hpp" -#include "arch/memory/cpu/msr.hpp" #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" -- cgit v1.2.3