From c5151739698620e77622423c109e638f903f01c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 10 Mar 2025 13:42:38 +0000 Subject: Adjust register segment descriptors to possible states --- .../descriptor_table/access_byte.hpp | 60 +++++++--------- .../descriptor_table/gdt_flags.hpp | 49 ++++++++------ .../descriptor_table/segment_descriptor.hpp | 2 - .../descriptor_table/segment_descriptor_type.hpp | 27 ++++++++ .../descriptor_table/type_field.hpp | 79 ++++++++++++++++++++++ 5 files changed, 157 insertions(+), 60 deletions(-) create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor_type.hpp create mode 100644 arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp (limited to 'arch/x86_64/include') diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp index 36b22ce..c510170 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp @@ -2,21 +2,16 @@ #ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP #define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_ACCESS_BYTE_HPP +#include "arch/context_switching/descriptor_table/type_field.hpp" + #include -#include -#include namespace teachos::arch::context_switching::descriptor_table { - enum class privilege_level - { - KERNEL = 0, - ADMIN = 1, - PRIVILEGED_USER = 2, - USER = 3 - }; - - /// @brief Defines the access byte of a Descriptor Table + /** + * @brief Defines helper function for all states that the access byte field of a segment descriptor can + * have. + */ struct access_byte { /** @@ -24,21 +19,17 @@ namespace teachos::arch::context_switching::descriptor_table */ enum bitset : uint8_t { - PRESENT = 1U << 0U, ///< Present bit; Allows an entry to refer to a valid segment. - ///< Must be set (1) for any valid segment. - PRIVILEGE_LEVEL = 1U << 1U | 1 << 2U, ///< Descriptor privilege level field. - ///< Contains the CPU Privilege level of the segment. - DESCRIPTOR_TYPE = 1U << 3U, ///< Defines a system segment (if 0) or a code/data segment (if 1). - EXECUTABLE = 1U << 4U, ///< Defines a data segment (if 0) or a code segment which can be executed from (if 1). - CONFORMING = 1U << 5U, ///< For data selectors: Direction bit - ///< Grows up (if 0), grows down (if 1) - ///< For code selectors: Conforming bit - ///< Code can only be executed from the DPL ring (if 0) - ///< Code can be executed from equal or lower DPL ring (if 1) - READ_WRITE = 1U << 6U, ///< For code segments: Readable bit - ///< For data segments: Writeable bit (read is always allowed) - ACCESSED = 1U << 7U ///< Set, when the segment is accessed. If GDT descriptor is stored in read only pages and - ///< this bit is set to 0, the CPU trying to set this bit will trigger a page fault. + PRESENT = 1U << 0U, ///< Present bit; Allows an entry to refer to a valid segment. + ///< Must be set (1) for any valid segment. + ACCESS_LEVEL_KERNEL = 0, ///< Highest privileged level used by the kernel to allow for full access of resources. + ACCESS_LEVEL_ADMIN = + 2, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more + ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. + ACCESS_LEVEL_PRIVILEGED_USER = + 4, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more than + ///< two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. + ACCESS_LEVEL_USER = 6, ///< Restricts access to only application and their specific memory. + DESCRIPTOR_TYPE = 1U << 3U, ///< Defines a system segment (if 0) or a code/data segment (if 1). }; /** @@ -47,11 +38,7 @@ namespace teachos::arch::context_switching::descriptor_table * @param flags Actual value read from the elf section header, which should be converted into a std::bitset, to * allow reading the state of single bits more easily. */ - explicit access_byte(uint8_t flags) - : flags(flags) - { - // Nothing to do - } + access_byte(uint8_t flags); /** * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. @@ -62,14 +49,14 @@ namespace teachos::arch::context_switching::descriptor_table * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. * @return Whether the given flags are a subset or equivalent with the underlying std::bitset. */ - auto contains_flags(std::bitset<8U> other) const -> bool; + auto contains_flags(std::bitset<4U> other) const -> bool; /** - * @brief Returns the privilege level of the current access_byte + * @brief Returns the type field of the access byte. * - * @return privilege_level + * @return Copy of the underlying type field bits. */ - auto get_privilege_level() const -> privilege_level; + auto get_type_field() const -> type_field; /** * @brief Allows to compare the underlying std::bitset of two instances. @@ -80,7 +67,8 @@ namespace teachos::arch::context_switching::descriptor_table auto operator==(access_byte const & other) const -> bool = default; private: - std::bitset<8U> flags; ///< Underlying bitset used to read the flags from + std::bitset<4U> _flags; ///< Underlying bitset used to read the flags from. + type_field _type; ///< Field specifying the type of the segment descriptor and its settings. }; } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp index 83a7c06..ef8f2fa 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp @@ -1,16 +1,15 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GDT_FLAGS_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GDT_FLAGS_HPP + +#include "arch/context_switching/descriptor_table/segment_descriptor_type.hpp" #include -#include namespace teachos::arch::context_switching::descriptor_table { /** - * @brief Defines helper function for all states that the global descriptor flags of a segment descriptor can + * @brief Defines helper function for all states that the flags field of a segment descriptor can * have. - * - * @note See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. */ struct gdt_flags { @@ -19,27 +18,33 @@ namespace teachos::arch::context_switching::descriptor_table */ enum bitset : uint8_t { - GRANULARITY = 1U << 0U, ///< Indicates the size the Limit value in the segement descriptor is scaled by 1 Byte - ///< blocks if the bit is not set or by 4 KiB blocks if the bit is set. - PROTECTED_MODE_SEGMENT_16_OR_32_BIT_SIZE = 1U << 1U, ///< Descriptor defines either a 16-bit protected mdoe - ///< segment if bit is not set or 32-bit if the bit is set. - ENABLE_LONG_MODE = 1U << 2U ///< If set the descriptor defines a 64-bit code segment, when set - ///< PROTECTED_MODE_SEGMENT_16_OR_32_BIT_SIZE should always be clear. For other types - ///< of segments bit should not be set. + GRANULARITY = 1U << 0U, ///< Indicates the size the Limit value in the segement descriptor is scaled by 1 Byte + ///< blocks if the bit is not set or by 4 KiB blocks if the bit is set. + DEFAULT_LENGTH = 1U << 1U, ///< Indicates the default length for code segments with effective addresses and + ///< operands. Enable for 32 bit, 16 bit otherwise. + STACK_POINTER_SIZE = 1U << 1U, ///< Specifies the size of the Stack Pointer (SP) for stack segments used for + ///< implicit stack operations. Enable for 32 bit, 16 bit otherwise. + UPPER_BOUND = 1U << 1U, ///< Specifies the upper bound of the segment for expand down data segment. Enable for 5 + ///< GiB, 4 KiB otherwise. + LENGTH = 1U << 2U ///< Defines in IA-32e mode (64-bit code and 32-bit compatability mode) if the segment contains + ///< 64-bit code. Otherwise this bit should always be 0. Enable if instructions are executed in + ///< 64-bit code, otherwis they are executed in compatability 32-bit mode. If bis is set the + ///< DEFAULT_LENGTH bis needs to be 0 }; /** * @brief Constructor. * * @param flags Actual value read from the elf section header, which should be converted into a std::bitset, to - * allow reading the state of single bits more easily. Only the first 3 bit of the value will actually be converted - * into the std::bitset, because the latter 4 bits are not relevant and the 4th bit is reserved. + * allow reading the state of single bits more easily. Only the rightmost 3 bit of the value will actually be + * converted into the std::bitset, because the leftmost 4 bit are irrelevant and the 4th bit is reserved. + * + * @param type Depending on the segment descriptor type some of the passed bits are ignored. For system segment only + * the first bit Granularity is relevant, for the data segment the 3rd bit Length is irrelevant and for the code + * segment all bits are relevant. Bits that are not relevant will simply not be read and saved into the underlying + * flags std::bitset. */ - explicit gdt_flags(uint8_t flags) - : flags(flags >> 5U) - { - // Nothing to do - } + gdt_flags(uint8_t flags, segment_descriptor_type type); /** * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. @@ -61,8 +66,8 @@ namespace teachos::arch::context_switching::descriptor_table auto operator==(gdt_flags const & other) const -> bool = default; private: - std::bitset<4U> flags; ///< Underlying bitset used to read the flags from. + std::bitset<4U> _flags; ///< Underlying bitset used to read the flags from. }; } // namespace teachos::arch::context_switching::descriptor_table -#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_GDT_FLAGS_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp index 8428dfa..b7665d9 100644 --- a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp @@ -4,8 +4,6 @@ #include "arch/context_switching/descriptor_table/gdt_flags.hpp" #include -#include -#include namespace teachos::arch::context_switching::descriptor_table { diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor_type.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor_type.hpp new file mode 100644 index 0000000..4815fca --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor_type.hpp @@ -0,0 +1,27 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP + +#include + +namespace teachos::arch::context_switching::descriptor_table +{ + /** + * @brief Possible overlying types of the segment descriptor. Allowing to discern between the major types, which + * result in different handling of the actual data contained in the descriptor. + */ + enum class segment_descriptor_type : uint8_t + { + SYSTEM_SEGMENT, ///< The segment is of type system, is distinguished by the Descriptor Type field in the Access + ///< Byte. Can be further distinguised to specific system segment types using the Type Field in the + ///< Access Byte. + DATA_SEGMENT, ///< The segment is of type data, is is distinguished by the Descriptor Type field in the Access + ///< Byte and the first bit of the Type Field in the Access Byte. Can be further distinguised to + ///< specific data segment types using the the remaining bits in the Type Field in the Access Byte. + CODE_SEGMENT, ///< The segment is of type code, is is distinguished by the Descriptor Type field in + ///< the Access Byte and the first bit of the Type Field in the Access Byte. Can be + ///< further distinguised to specific data segment types using the the remaining bits in + ///< the Type Field in the Access Byte. + }; +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_SEGMENT_DESCRIPTOR_TYPES_HPP diff --git a/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp b/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp new file mode 100644 index 0000000..88e25cf --- /dev/null +++ b/arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp @@ -0,0 +1,79 @@ +#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TYPE_FIELD_HPP +#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TYPE_FIELD_HPP + +#include "arch/context_switching/descriptor_table/segment_descriptor_type.hpp" + +#include + +namespace teachos::arch::context_switching::descriptor_table +{ + /** + * @brief Defines helper function for all states that the flags field of a segment descriptor can + * have. + */ + struct type_field + { + /** + * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + */ + enum bitset : uint8_t + { + TYPE = 1U << 0U, ///< Further defines the actual type of the segment. If enabled this segment is a code segment, + ///< otherwise its a data segment. + EXPAND_UP = 1U << 1U, ///< Indicates if the expansion direction is up or down in data segments. If enabled the + ///< data segment expands downwards, otherwise it expands upwards. + CONFORMING = + 1U << 1U, ///< Indicates if the code is allowed to be executed by different access levels + ///< (higher or lower) in code segments. If enabled the code segment allows access, otherwise + ///< access from different privilege levels with throw a General-Protectione exception. + WRITABLE = 1U << 2U, ///< Indicates if the data segment is writable or not. If enabled the code segment allows + ///< read and write access, otherwise only read access is possible. + READABLE = 1U << 2U, ///< Indicates if the code segment is readable or not. If enabled the code segment allows + ///< read and execute access, otherwise only executable access is possible. + ACCESSED = + 1U + << 3U, ///< Whether the segment has been accessed since the last time the operating system has cleared the + ///< flag. If enabled it has been accessed, otherwise it has not been accessed since the last clear. + LOCAL_DESCRIPTOR_TABLE = 2, ///< The actual type of sytem segment is a local descriptor table. + TASK_STATE_SEGMENT_AVAILABLE = + 9, ///< The actual type of sytem segment is a task state segment that is still available. + TASK_STATE_SEGMENT_BUSY = 11, ///< The actual type of sytem segment is a task state segment that is currently in + ///< use and therefore busy. + CALL_GATE = 11, ///< The actual type of sytem segment is a call gate. + INTERRUPT_GATE = 14, ///< The actual type of sytem segment is a interrupt gate. + TRAP_GATE = 15 ///< The actual type of sytem segment is a trap gate. + }; + + /** + * @brief Constructor. + * + * @param flags Actual value read from the elf section header, which should be converted into a std::bitset, to + * allow reading the state of single bits more easily. + */ + type_field(uint8_t flags); + + /** + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. + * + * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng + * std::bitset. Any additional bits that are set are not relevant. + * + * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. + * @return Whether the given flags are a subset or equivalent with the underlying std::bitset. + */ + auto contains_flags(std::bitset<4U> other) const -> bool; + + /** + * @brief Allows to compare the underlying std::bitset of two instances. + * + * @param other Other instance that we want to compare with. + * @return Whether the underlying std::bitset of both types is the same. + */ + auto operator==(type_field const & other) const -> bool = default; + + private: + std::bitset<4U> _flags; ///< Underlying bitset used to read the flags from. + }; +} // namespace teachos::arch::context_switching::descriptor_table + +#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_DESCRIPTOR_TABLE_TYPE_FIELD_HPP -- cgit v1.2.3