aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86_64/CMakeLists.txt1
-rw-r--r--arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp60
-rw-r--r--arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp49
-rw-r--r--arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp2
-rw-r--r--arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor_type.hpp27
-rw-r--r--arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp79
-rw-r--r--arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp15
-rw-r--r--arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp24
-rw-r--r--arch/x86_64/src/context_switching/descriptor_table/type_field.cpp12
9 files changed, 201 insertions, 68 deletions
diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt
index 8cb1ca2..19c71be 100644
--- a/arch/x86_64/CMakeLists.txt
+++ b/arch/x86_64/CMakeLists.txt
@@ -88,6 +88,7 @@ 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"
)
#[============================================================================[
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 <bitset>
-#include <cstddef>
-#include <cstdint>
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 <bitset>
-#include <cstdint>
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 <bitset>
-#include <cstddef>
-#include <cstdint>
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 <cstdint>
+
+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 <bitset>
+
+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
diff --git a/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp b/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp
index 15a0947..7a2b0b0 100644
--- a/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp
+++ b/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp
@@ -1,14 +1,15 @@
#include "arch/context_switching/descriptor_table/access_byte.hpp"
-#include <bitset>
-
namespace teachos::arch::context_switching::descriptor_table
{
- auto access_byte::contains_flags(std::bitset<8U> other) const -> bool { return (flags & other) == other; }
-
- auto access_byte::get_privilege_level() const -> privilege_level
+ access_byte::access_byte(uint8_t flags)
+ : _flags(flags)
+ , _type(flags)
{
- constexpr uint8_t PRIVILEGE_MASK = 0b0110'0000;
- return static_cast<privilege_level>(flags.to_ulong() & PRIVILEGE_MASK);
+ // Nothing to do.
}
+
+ auto access_byte::contains_flags(std::bitset<4U> other) const -> bool { return (_flags & other) == other; }
+
+ auto access_byte::get_type_field() const -> type_field { return _type; }
} // namespace teachos::arch::context_switching::descriptor_table
diff --git a/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp b/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp
index 8a05956..8e1e939 100644
--- a/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp
+++ b/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp
@@ -1,6 +1,28 @@
#include "arch/context_switching/descriptor_table/gdt_flags.hpp"
+#include "arch/exception_handling/assert.hpp"
+
namespace teachos::arch::context_switching::descriptor_table
{
- auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool { return (flags & other) == other; }
+ gdt_flags::gdt_flags(uint8_t flags, segment_descriptor_type type)
+ : _flags(flags << 5U)
+ {
+ switch (type)
+ {
+ case segment_descriptor_type::SYSTEM_SEGMENT:
+ _flags.set(2, false);
+ _flags.set(3, false);
+ break;
+ case segment_descriptor_type::DATA_SEGMENT:
+ _flags.set(3, false);
+ break;
+ case segment_descriptor_type::CODE_SEGMENT:
+ exception_handling::assert((contains_flags(LENGTH) && !contains_flags(DEFAULT_LENGTH)) ||
+ !contains_flags(LENGTH),
+ "[GDT] Flags of code segment descriptor has both ");
+ break;
+ }
+ }
+
+ auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool { return (_flags & other) == other; }
} // namespace teachos::arch::context_switching::descriptor_table
diff --git a/arch/x86_64/src/context_switching/descriptor_table/type_field.cpp b/arch/x86_64/src/context_switching/descriptor_table/type_field.cpp
new file mode 100644
index 0000000..d967a97
--- /dev/null
+++ b/arch/x86_64/src/context_switching/descriptor_table/type_field.cpp
@@ -0,0 +1,12 @@
+#include "arch/context_switching/descriptor_table/type_field.hpp"
+
+namespace teachos::arch::context_switching::descriptor_table
+{
+ type_field::type_field(uint8_t flags)
+ : _flags(flags)
+ {
+ // Nothing to do.
+ }
+
+ auto type_field::contains_flags(std::bitset<4U> other) const -> bool { return (_flags & other) == other; }
+} // namespace teachos::arch::context_switching::descriptor_table