diff options
| author | Matteo Gmür <matteo.gmuer1@ost.ch> | 2025-05-02 14:49:06 +0000 |
|---|---|---|
| committer | Matteo Gmür <matteo.gmuer1@ost.ch> | 2025-05-02 14:49:06 +0000 |
| commit | 099a7fbbc35a71f98553fa39899f2d17c555242f (patch) | |
| tree | b80f9dfef02d223e08af123bf5adff41a98bc2bc /arch/x86_64 | |
| parent | 7c045d8ded72017ff11fd4b9b02148987b944caf (diff) | |
| download | teachos-099a7fbbc35a71f98553fa39899f2d17c555242f.tar.xz teachos-099a7fbbc35a71f98553fa39899f2d17c555242f.zip | |
Finish implementing 8-byte GDT entries and syscall arg loads.
Diffstat (limited to 'arch/x86_64')
16 files changed, 225 insertions, 232 deletions
diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 58afdb5..21dbddd 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -97,7 +97,6 @@ target_sources("_context" PRIVATE "src/context_switching/segment_descriptor_table/gdt_flags.cpp" "src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp" "src/context_switching/segment_descriptor_table/global_descriptor_table.cpp" - "src/context_switching/segment_descriptor_table/segment_descriptor.cpp" "src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp" "src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp" "src/context_switching/main.cpp" diff --git a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp index 8748448..5be449f 100644 --- a/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp +++ b/arch/x86_64/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp @@ -79,11 +79,11 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table auto operator|=(std::bitset<3U> other) -> void; /** - * @brief Combines all bits in the underlying data in the correct order to return a raw value containing all bits. + * @brief Cast the underlying data into a combined 16-bit form, that contains all data. * * @return Underlying value combined into it's full size. */ - operator uint16_t() const { return static_cast<uint64_t>(_flags) | (static_cast<uint64_t>(_index) << 3U); } + operator uint16_t() const; private: uint8_t _flags : 3 = {}; ///< Underlying bits used to read the flags from. diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp index 84a24a2..44f2692 100644 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp +++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp @@ -30,7 +30,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table * @note This method should only be called after update_gdtr() and a far jump has been * executed. Because before that trying to access the segment will cause an exception. */ - auto update_task_state_segment_register() -> void; + auto update_tss_register() -> void; } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp index c54647d..292ff70 100644 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp +++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp @@ -1,24 +1,13 @@ #ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP #define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_GLOBAL_DESCRIPTOR_TABLE_POINTER_HPP -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp" -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp" #include "arch/stl/vector.hpp" #include <cstdint> namespace teachos::arch::context_switching::segment_descriptor_table { - struct __attribute__((packed, aligned(8))) global_descriptor_table - { - segment_descriptor_base null; - segment_descriptor_base kernel_code; - segment_descriptor_base kernel_data; - segment_descriptor_base user_code; - segment_descriptor_base user_data; - segment_descriptor_base tss_low; - segment_descriptor_extension tss_high; - }; + using global_descriptor_table = stl::vector<uint64_t>; /** * @brief Represents a pointer to the Global Descriptor Table (GDT). @@ -36,7 +25,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table /** * @brief Constructor. */ - global_descriptor_table_pointer(uint16_t table_length, seg_desc * address); + global_descriptor_table_pointer(uint16_t table_length, uint64_t * address); /** * @brief Defaulted three-way comparsion operator. @@ -45,7 +34,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table private: uint16_t table_length = {}; ///< The amount of segment descriptor entries in the global descriptor table - 1. - seg_desc * address = {}; ///< Non-owning pointer to the GDT base address. + uint64_t * address = {}; ///< Non-owning pointer to the GDT base address. }; } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor.hpp deleted file mode 100644 index ccd604d..0000000 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP - -#include "arch/context_switching/segment_descriptor_table/access_byte.hpp" -#include "arch/context_switching/segment_descriptor_table/gdt_flags.hpp" -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - __extension__ typedef __int128 int128_t; - __extension__ typedef unsigned __int128 uint128_t; - - struct seg_desc - { - private: - uint64_t : 64; ///< Makes sure the struct is 8-Bytes big - }; - - /** - * @brief Defines helper function for all states and the actual data the segment descriptor can have. - */ - struct [[gnu::packed]] segment_descriptor - { - /** - * @brief Default Constructor. - */ - segment_descriptor() = default; - - /** - * @brief Constructor. - * - * @note Created segment descriptor copies the given bytes into theese components ending with a 32 bit reserved - * field that has to be used, because the 64-bit segment descriptor needs to be big enough for two 32-bit segment - * descriptor. - * - 8 bit Access Type - * - 4 bit Flags - * - 64 bit Base Address - * - 20 bit Limit - * - * @param flags Copies the bits set from the given data into the individual components of a segment - * descriptor. - */ - explicit segment_descriptor(uint128_t flags); - - /** - * @brief Constructor. - * - * @param access_byte, flags, base, limit Copies the bits set from the given data into the individual components of - * a segment descriptor. - */ - segment_descriptor(access_byte access_byte, gdt_flags flags, uint64_t base, std::bitset<20U> limit); - - auto get_limit_1() -> uint16_t; - auto get_base_1() -> uint32_t; - auto get_access() -> access_byte; - auto get_flag() -> gdt_flags; - auto get_base_2() -> uint64_t; - - /** - * @brief Calculates the underlying segment type that this segement descriptor is describing. - */ - auto get_segment_type() const -> segment_descriptor_type; - - /** - * @brief Allows to compare the underlying bits of two instances. - * - * @param other Other instance that we want to compare with. - * @return Whether the underlying set bits of both types are the same. - */ - auto operator==(segment_descriptor const & other) const -> bool = default; - - private: - // The order in private variables starts for the first variable being the rightmost bit. - uint16_t _limit_1 = {}; ///< First part of the limit field (0 - 15) - uint32_t _base_1 : 24 = {}; ///< First part of the base field (16 - 39) - access_byte _access = {}; ///< Access byte field (40 - 47) - gdt_flags _flag = {}; ///< Second part of the limit field + Flags field (48 - 55) - uint64_t _base_2 : 40 = {}; ///< Second part of the base field (56 - 95) - uint32_t : 32; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) - }; -} // namespace teachos::arch::context_switching::segment_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_HPP diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp index 18c9da1..933fb4d 100644 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp +++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp @@ -3,7 +3,6 @@ #include "arch/context_switching/segment_descriptor_table/access_byte.hpp" #include "arch/context_switching/segment_descriptor_table/gdt_flags.hpp" -#include "arch/context_switching/segment_descriptor_table/segment_descriptor.hpp" #include "arch/context_switching/segment_descriptor_table/segment_descriptor_type.hpp" namespace teachos::arch::context_switching::segment_descriptor_table @@ -11,7 +10,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table /** * @brief Defines helper function for all states and the actual data the segment descriptor can have. */ - struct [[gnu::packed]] segment_descriptor_base : seg_desc + struct [[gnu::packed]] segment_descriptor_base { /** * @brief Default Constructor. @@ -20,14 +19,54 @@ namespace teachos::arch::context_switching::segment_descriptor_table /** * @brief Constructor. + * + * @note Created segment descriptor copies the given bytes into these components requiring the space of one + * segment descriptor entry in the global descriptor table being 64-bit. + * - 8 bit Access Type + * - 4 bit Flags + * - 32 bit Base Address + * - 20 bit Limit + * + * @param flags Copies the bits set from the given data into the individual components of a segment + * descriptor. */ - segment_descriptor_base(segment_descriptor segment_descriptor); + explicit segment_descriptor_base(uint64_t flags); + + /** + * @brief Constructor. + * + * @param access_byte, flags, base, limit Copies the bits set from the given data into the individual components of + * a segment descriptor. + */ + segment_descriptor_base(access_byte access_byte, gdt_flags flags, uint32_t base, std::bitset<20U> limit); + + /** + * @brief Calculates the underlying segment type that this segement descriptor is describing. + */ + auto get_segment_type() const -> segment_descriptor_type; + + /** + * @brief Cast the underlying data into a combined 64-bit form, that contains all data. + * + * @return Underlying value combined into it's full size. + */ + operator uint64_t() const; + + /** + * @brief Allows to compare the underlying bits of two instances. + * + * @param other Other instance that we want to compare with. + * @return Whether the underlying set bits of both types are the same. + */ + auto operator==(segment_descriptor_base const & other) const -> bool = default; private: + // The order in private variables starts for the first variable being the rightmost bit. uint16_t _limit_1 = {}; ///< First part of the limit field (0 - 15) uint32_t _base_1 : 24 = {}; ///< First part of the base field (16 - 39) access_byte _access = {}; ///< Access byte field (40 - 47) gdt_flags _flag = {}; ///< Second part of the limit field + Flags field (48 - 55) + uint8_t _base_2 = {}; ///< Second part of the base field (56 - 63) }; } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp index 0b724f2..40bcc8a 100644 --- a/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp +++ b/arch/x86_64/include/arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp @@ -1,16 +1,17 @@ #ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_EXTENSION_HPP #define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SEGMENT_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_EXTENSION_HPP -#include "arch/context_switching/segment_descriptor_table/segment_descriptor.hpp" - -#include <cstdint> +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp" namespace teachos::arch::context_switching::segment_descriptor_table { + __extension__ typedef __int128 int128_t; + __extension__ typedef unsigned __int128 uint128_t; + /** * @brief Defines helper function for all states and the actual data the segment descriptor can have. */ - struct [[gnu::packed]] segment_descriptor_extension : seg_desc + struct [[gnu::packed]] segment_descriptor_extension { /** * @brief Default Constructor. @@ -19,12 +20,54 @@ namespace teachos::arch::context_switching::segment_descriptor_table /** * @brief Constructor. + * + * @note Created segment descriptor copies the given bytes into these components requiring the space of two + * segment descriptor entry in the global descriptor table being 128-bit. Ending with a 32 bit reserved + * field that has to be used, because the segment descriptor needs to be big enough for two segment + * descriptor entries. + * - 8 bit Access Type + * - 4 bit Flags + * - 64 bit Base Address + * - 20 bit Limit + * + * @param flags Copies the bits set from the given data into the individual components of a segment + * descriptor. + */ + explicit segment_descriptor_extension(uint128_t flags); + + /** + * @brief Constructor. + * + * @param access_byte, flags, base, limit Copies the bits set from the given data into the individual components of + * a segment descriptor. + */ + segment_descriptor_extension(access_byte access_byte, gdt_flags flags, uint64_t base, std::bitset<20U> limit); + + /** + * @brief Returns the underlying base segment descriptor, being the first part of the segment descriptor consisting + * of two entries in the global descriptor table. + */ + auto get_first_gdt_entry() const -> segment_descriptor_base; + + /** + * @brief Returns the underlying extension to the segment descriptor, being the second part of the segment + * descriptor consiting of two entries in the global descriptor table. + */ + auto get_second_gdt_entry() const -> uint64_t; + + /** + * @brief Allows to compare the underlying bits of two instances. + * + * @param other Other instance that we want to compare with. + * @return Whether the underlying set bits of both types are the same. */ - segment_descriptor_extension(segment_descriptor segment_descriptor); + auto operator==(segment_descriptor_extension const & other) const -> bool = default; private: - uint64_t _base_2 : 40 = {}; ///< Second part of the base field (56 - 95) - uint32_t : 32; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) + // The order in private variables starts for the first variable being the rightmost bit. + segment_descriptor_base _base = {}; ///< Base Segment Descriptor representing single entry in GDT (0 - 63) + uint32_t _base_3 = {}; ///< Third part of the base field (63 - 95) + uint32_t : 32; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) }; } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp index 0e29356..8568447 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp @@ -8,4 +8,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table } auto segment_selector::operator|=(std::bitset<3U> other) -> void { _flags |= other.to_ulong(); } + + segment_selector::operator uint16_t() const { return *reinterpret_cast<uint16_t const *>(this); } } // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 5901998..7449d84 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -31,14 +31,14 @@ namespace teachos::arch::context_switching auto reload_gdtr() -> void { - // asm volatile("pushq $0x8\n\t" // Push new CS - // "lea 1f(%%rip), %%rax\n\t" // Get address of label 1 into RAX - // "pushq %%rax\n\t" // Push return address - // "lretq\n" // Far return (loads CS:RIP) - // "1:\n\t" // Label to return to - // : - // : - // : "rax", "memory"); + /*asm volatile("pushq $0x8\n\t" // Push new CS + "lea 1f(%%rip), %%rax\n\t" // Get address of label 1 into RAX + "pushq %%rax\n\t" // Push return address + "lretq\n" // Far return (loads CS:RIP) + "1:\n\t" // Label to return to + : + : + : "rax", "memory");*/ kernel::cpu::call(KERNEL_CODE_POINTER); } @@ -57,21 +57,33 @@ namespace teachos::arch::context_switching // Actual Source: https://man7.org/linux/man-pages/man2/syscall.2.html More cleare documentation: // https://sys.readthedocs.io/en/latest/doc/05_calling_system_calls.html - uint64_t new_value = 60U; + uint64_t syscall_number = 60U; asm volatile("mov %[input], %%rax" : /* no output from call */ - : [input] "r"(new_value) + : [input] "r"(syscall_number) : "memory"); asm volatile("syscall"); - video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", - video::vga::text::common_attributes::green_on_black); + // TODO: Reading RAX value does not work because the read itself changes the RAX value?! + // asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_value)); + + // TODO: Causes a general protection fault after the sysreturn? + // If removed instead it will cause a general protection fault after leaving this main method to return to kernel + // mode. But CS and SS are still configured for User mode. + /*video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", + video::vga::text::common_attributes::green_on_black);*/ } auto syscall_handler() -> void { - uint64_t syscall_number{}; + uint64_t syscall_number, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5 = {}; asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_number)); + asm volatile("mov %%rdi, %[output]" : [output] "=r"(arg_0)); + asm volatile("mov %%rsi, %[output]" : [output] "=r"(arg_1)); + asm volatile("mov %%rdx, %[output]" : [output] "=r"(arg_2)); + asm volatile("mov %%r10, %[output]" : [output] "=r"(arg_3)); + asm volatile("mov %%r8, %[output]" : [output] "=r"(arg_4)); + asm volatile("mov %%r9, %[output]" : [output] "=r"(arg_5)); switch (syscall_number) { @@ -85,7 +97,17 @@ namespace teachos::arch::context_switching break; } - asm volatile("sysretq"); + uint64_t result = 0U; + asm volatile("mov %[input], %%rax" + : /* no output from call */ + : [input] "r"(result) + : "memory"); + + // Use SYSRET instead of SYSRETQ, because the latter would add 0x10 to bits [48:63] of IA32_STAR_ADDRESS for the + // Code Segment. But only add 0x8 to bits [48:63] of IA32_STAR_ADDRESS for the Stack Segment, which means either + // the Stack Segment or Code Segment is wrong. Whereas the former does not add 0x10 for the Code Segment and + // therefore fixes the aformentioned issue. + asm volatile("sysret"); } auto enable_systemcall() -> void @@ -94,9 +116,9 @@ namespace teachos::arch::context_switching kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t user_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t star_value = (kernel_cs << 32) | (user_cs << 48); + uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; + uint64_t const user_cs = USER_CODE_SEGMENT_SELECTOR; + uint64_t const star_value = (kernel_cs << 32) | (user_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); @@ -116,7 +138,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::update_interrupt_descriptor_table_register(); reload_gdtr(); - segment_descriptor_table::update_task_state_segment_register(); + segment_descriptor_table::update_tss_register(); kernel::cpu::set_interrupt_flag(); initalized = true; diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp index dd22603..d692e51 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp @@ -1,8 +1,6 @@ #include "arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp" -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp" #include "arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp" -#include "arch/context_switching/segment_descriptor_table/task_state_segment.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/gdtr.hpp" #include "arch/kernel/cpu/tr.hpp" @@ -12,7 +10,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table namespace { auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_byte access_level) - -> segment_descriptor + -> segment_descriptor_base { uint64_t const base = 0x0; std::bitset<20U> const limit{0xFFFFF}; @@ -29,57 +27,53 @@ namespace teachos::arch::context_switching::segment_descriptor_table access_level |= access_byte::WRITABLE; } - segment_descriptor const segment_descriptor{access_level, flags, base, limit}; - return segment_descriptor; + segment_descriptor_base const segment_descriptor_base{access_level, flags, base, limit}; + return segment_descriptor_base; } - auto create_tss_descriptor(task_state_segment * tss) -> segment_descriptor + auto create_tss_descriptor(task_state_segment * tss) -> segment_descriptor_extension { constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; access_byte const tss_access_byte{access_byte::PRESENT | access_byte::DESCRIPTOR_LEVEL_KERNEL | access_byte::TASK_STATE_SEGMENT_AVAILABLE}; gdt_flags const tss_gdt_flags{0U, TSS_LIMIT}; - segment_descriptor const tss_descriptor{tss_access_byte, tss_gdt_flags, reinterpret_cast<uint64_t>(tss), - TSS_LIMIT}; + segment_descriptor_extension const tss_descriptor{tss_access_byte, tss_gdt_flags, reinterpret_cast<uint64_t>(tss), + TSS_LIMIT}; return tss_descriptor; } - auto create_gdt() -> global_descriptor_table * + auto create_gdt() -> global_descriptor_table { - segment_descriptor_base const null_segment{segment_descriptor{0}}; - segment_descriptor_base const kernel_code_segment{ - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL)}; - segment_descriptor_base const kernel_data_segment{ - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL)}; - segment_descriptor_base const user_code_segment{ - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER)}; - segment_descriptor_base const user_data_segment{ - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER)}; + segment_descriptor_base const null_segment{0}; + segment_descriptor_base const kernel_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor_base const kernel_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor_base const user_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); + segment_descriptor_base const user_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); // Task State Segment needs to be kept alive static auto tss = new task_state_segment(); - segment_descriptor const tss_descriptor = create_tss_descriptor(tss); - segment_descriptor_base const tss_descriptor_base{tss_descriptor}; - segment_descriptor_extension const tss_descriptor_extension{tss_descriptor}; - - decltype(auto) gdt = new global_descriptor_table{}; - gdt->null = null_segment; - gdt->kernel_code = kernel_code_segment; - gdt->kernel_data = kernel_data_segment; - gdt->user_code = user_code_segment; - gdt->user_data = user_data_segment; - gdt->tss_low = tss_descriptor_base; - gdt->tss_high = tss_descriptor_extension; - - return gdt; - }; + segment_descriptor_extension const tss_descriptor = create_tss_descriptor(tss); + + global_descriptor_table global_descriptor_table{null_segment, + kernel_code_segment, + kernel_data_segment, + user_code_segment, + user_data_segment, + tss_descriptor.get_first_gdt_entry(), + tss_descriptor.get_second_gdt_entry()}; + return global_descriptor_table; + } } // namespace auto get_or_create_gdt() -> global_descriptor_table & { // Global Descriptor Table needs to be kept alive - static global_descriptor_table * gdt = create_gdt(); - return *gdt; + static global_descriptor_table gdt = create_gdt(); + return gdt; } auto update_gdtr() -> void @@ -88,7 +82,8 @@ namespace teachos::arch::context_switching::segment_descriptor_table // Calculate the size of the gdt in bytes - 1. This subtraction occurs because the maximum value of Size is 65535, // while the GDT can be up to 65536 bytes in length (8192 entries). Further, no GDT can have a size of 0 bytes. - global_descriptor_table_pointer gdt_pointer{static_cast<uint16_t>((7 * sizeof(seg_desc)) - 1), &gdt.null}; + uint16_t gdt_size = static_cast<uint16_t>((gdt.size() * sizeof(segment_descriptor_base)) - 1); + global_descriptor_table_pointer gdt_pointer{gdt_size, gdt.data()}; kernel::cpu::load_global_descriptor_table(gdt_pointer); auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); @@ -97,13 +92,13 @@ namespace teachos::arch::context_switching::segment_descriptor_table "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); } - auto update_task_state_segment_register() -> void + auto update_tss_register() -> void { - get_or_create_gdt(); + decltype(auto) gdt = get_or_create_gdt(); // Load task state segment descriptor from the last element in the global descriptor table, done by calculating - // offset in bytes to the start of the segment descriptor (5 * 16) = 80 - uint16_t const tss_selector = (7 - 1) * sizeof(segment_descriptor_table::segment_descriptor); + // offset in bytes to the start of the segment descriptor (5 * 8) = 40 + uint16_t tss_selector = (gdt.size() * sizeof(segment_descriptor_base)) - sizeof(segment_descriptor_extension); kernel::cpu::load_task_register(tss_selector); auto const stored_task_register = kernel::cpu::store_task_register(); diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp index b7d2da4..79088b8 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp @@ -2,7 +2,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table { - global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, seg_desc * address) + global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, uint64_t * address) : table_length(table_length) , address(address) { diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp deleted file mode 100644 index e74156b..0000000 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "arch/context_switching/segment_descriptor_table/segment_descriptor.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - segment_descriptor::segment_descriptor(uint128_t flags) - : _limit_1(flags) - , _base_1(flags >> 16U) - , _access(flags >> 40U) - , _flag(flags >> 52U, flags >> 48U) - , _base_2(flags >> 56U) - { - // Nothing to do. - } - - segment_descriptor::segment_descriptor(access_byte access_byte, gdt_flags flags, uint64_t base, - std::bitset<20U> limit) - : _limit_1(limit.to_ulong()) - , _base_1(base) - , _access(access_byte) - , _flag(flags) - , _base_2(base >> 24U) - { - // Nothing to do - } - - aut |
