aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Imhof <fabian.imhof@ost.ch>2025-03-13 09:36:00 +0000
committerFabian Imhof <fabian.imhof@ost.ch>2025-03-13 09:36:00 +0000
commitb8a0024ee71a64ec0e87a1e2d0c0c7280dc954e6 (patch)
treed4d8ee6a97074594c0c0e99a5d8706a4eadb178e
parent569cf73d1fa14ec11afbb37464d2c356d55d64b4 (diff)
downloadteachos-b8a0024ee71a64ec0e87a1e2d0c0c7280dc954e6.tar.xz
teachos-b8a0024ee71a64ec0e87a1e2d0c0c7280dc954e6.zip
create GDT and fix segment descriptor bit order
-rw-r--r--CMakeLists.txt1
-rw-r--r--arch/x86_64/include/arch/context_switching/descriptor_table/access_byte.hpp23
-rw-r--r--arch/x86_64/include/arch/context_switching/descriptor_table/gdt_flags.hpp27
-rw-r--r--arch/x86_64/include/arch/context_switching/descriptor_table/segment_descriptor.hpp23
-rw-r--r--arch/x86_64/include/arch/context_switching/descriptor_table/type_field.hpp33
-rw-r--r--arch/x86_64/include/arch/stl/vector.hpp2
-rw-r--r--arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp4
-rw-r--r--arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp2
-rw-r--r--arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp22
-rw-r--r--arch/x86_64/src/kernel/main.cpp50
10 files changed, 141 insertions, 46 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3717788..daf87b8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -144,6 +144,7 @@ target_link_libraries("_kernel" PRIVATE
"teachos::memory"
"teachos::exception"
"teachos::shared"
+ "teachos::context_switching"
)
#[============================================================================[
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 d1b579d..dc4de03 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
@@ -19,8 +19,7 @@ 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.
+ CODE_OR_DATA_SEGMENT = 1U << 0U, ///< Defines a system segment (if 0) or a code/data segment (if 1).
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
@@ -28,17 +27,23 @@ namespace teachos::arch::context_switching::descriptor_table
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.
- CODE_OR_DATA_SEGMENT = 1U << 3U, ///< Defines a system segment (if 0) or a code/data segment (if 1).
+ ACCESS_LEVEL_USER = 6, ///< Restricts access to only application and their specific memory.
+ PRESENT = 1U << 3U, ///< Present bit; Allows an entry to refer to a valid segment.
+ ///< Must be set (1) for any valid segment.
};
/**
+ * @brief Default Constructor.
+ */
+ access_byte() = default;
+
+ /**
* @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.
+ * @param flags Left-most four bits of the access_byte.
+ * @param type_field Right-most four bits of the access_byte representing the type_field.
*/
- access_byte(uint8_t flags);
+ access_byte(uint8_t flags, uint8_t type_field);
/**
* @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset.
@@ -67,8 +72,8 @@ namespace teachos::arch::context_switching::descriptor_table
auto operator==(access_byte const & other) const -> bool = default;
private:
- 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.
+ 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 bc6ecb7..f27284e 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
@@ -18,21 +18,26 @@ 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.
- 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.
+ LENGTH = 1U << 0U, ///< 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, otherwise they are executed in compatability 32-bit mode. If bis
+ ///< is set the DEFAULT_LENGTH bis needs to be 0
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
+ 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.
+ DEFAULT_LENGTH = 1U << 1U, ///< Indicates the default length for code segments with effective addresses and
+ ///< operands. Enable for 32 bit, 16 bit otherwise.
+ GRANULARITY = 1U << 2U, ///< Indicates the size the Limit value in the segment descriptor is scaled by 1 Byte
+ ///< blocks if the bit is not set or by 4 KiB blocks if the bit is set.
};
/**
+ * @brief Default Constructor.
+ */
+ gdt_flags() = default;
+
+ /**
* @brief Constructor.
*
* @param flags Actual value read from the elf section header, which should be converted into a std::bitset, to
@@ -61,7 +66,7 @@ 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
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 364e546..b5697e3 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
@@ -17,6 +17,11 @@ namespace teachos::arch::context_switching::descriptor_table
struct 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
@@ -33,16 +38,24 @@ namespace teachos::arch::context_switching::descriptor_table
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);
+
+ /**
* @brief Calculates the underlying segment type that this segement descriptor is describing.
*/
auto get_segment_type() const -> segment_descriptor_type;
private:
- uint32_t _reserved;
- access_byte _access;
- gdt_flags _flag;
- uint64_t _base;
- std::bitset<20U> _limit;
+ uint32_t _reserved = {};
+ access_byte _access = {};
+ gdt_flags _flag = {};
+ uint64_t _base = {};
+ std::bitset<20U> _limit = {};
};
} // namespace teachos::arch::context_switching::descriptor_table
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
index da61d38..3822f9c 100644
--- 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
@@ -18,22 +18,22 @@ namespace teachos::arch::context_switching::descriptor_table
*/
enum bitset : uint8_t
{
- CODE_SEGMENT = 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
+ << 0U, ///< 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.
+ WRITABLE = 1U << 1U, ///< 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 << 1U, ///< 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.
+ CONFORMING =
+ 1U << 2U, ///< 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.
+ EXPAND_DOWN = 1U << 2U, ///< Indicates if the expansion direction is up or down in data segments. If enabled the
+ ///< data segment expands downwards, otherwise it expands upwards.
+ CODE_SEGMENT = 1U << 3U, ///< Further defines the actual type of the segment. If enabled this segment is a code
+ ///< segment, otherwise its a data segment.
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.
@@ -45,6 +45,11 @@ namespace teachos::arch::context_switching::descriptor_table
};
/**
+ * @brief Default Constructor.
+ */
+ type_field() = default;
+
+ /**
* @brief Constructor.
*
* @param flags Actual value read from the elf section header, which should be converted into a std::bitset, to
@@ -72,7 +77,7 @@ namespace teachos::arch::context_switching::descriptor_table
auto operator==(type_field 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
diff --git a/arch/x86_64/include/arch/stl/vector.hpp b/arch/x86_64/include/arch/stl/vector.hpp
index b8bedf3..112af57 100644
--- a/arch/x86_64/include/arch/stl/vector.hpp
+++ b/arch/x86_64/include/arch/stl/vector.hpp
@@ -18,7 +18,7 @@ namespace teachos::arch::stl
struct vector
{
/**
- * @brief Defaulted constructor. Initalizes empty vector.
+ * @brief Default Constructor.
*/
vector() = default;
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 7a2b0b0..4e5459f 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
@@ -2,9 +2,9 @@
namespace teachos::arch::context_switching::descriptor_table
{
- access_byte::access_byte(uint8_t flags)
+ access_byte::access_byte(uint8_t flags, uint8_t type_field)
: _flags(flags)
- , _type(flags)
+ , _type(type_field)
{
// Nothing to do.
}
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 8fbf869..65f2e90 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
@@ -5,7 +5,7 @@
namespace teachos::arch::context_switching::descriptor_table
{
gdt_flags::gdt_flags(uint8_t flags)
- : _flags(flags << 5U)
+ : _flags(flags)
{
// Nothing to do.
}
diff --git a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp
index 57564f2..ab8eaba 100644
--- a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp
+++ b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp
@@ -4,7 +4,7 @@ namespace teachos::arch::context_switching::descriptor_table
{
segment_descriptor::segment_descriptor(uint128_t flags)
: _reserved(flags >> 96U)
- , _access((flags >> 40U) << 80U)
+ , _access((flags >> 44U) << 80U, (flags >> 40U) << 84U)
, _flag((flags >> 52U) << 72U)
, _base(((flags >> 64U) << 32U) << 32U | ((flags >> 56U) << 64U) << 24U | (flags >> 16U) << 88U)
, _limit(((flags >> 48U) << 72U) << 16U | flags << 112U)
@@ -12,13 +12,29 @@ namespace teachos::arch::context_switching::descriptor_table
// Nothing to do.
}
+ segment_descriptor::segment_descriptor(access_byte access_byte, gdt_flags flags, uint64_t base,
+ std::bitset<20U> limit)
+ : _reserved(0U)
+ , _access(access_byte)
+ , _flag(flags)
+ , _base(base)
+ , _limit(limit)
+ {
+ // Nothing to do
+ }
+
auto segment_descriptor::get_segment_type() const -> segment_descriptor_type
{
if (!_access.contains_flags(access_byte::CODE_OR_DATA_SEGMENT))
{
return segment_descriptor_type::SYSTEM_SEGMENT;
}
- return _access.get_type_field().contains_flags(type_field::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT
- : segment_descriptor_type::DATA_SEGMENT;
+
+ if (_access.get_type_field().contains_flags(type_field::CODE_SEGMENT))
+ {
+ return segment_descriptor_type::CODE_SEGMENT;
+ }
+
+ return segment_descriptor_type::DATA_SEGMENT;
}
} // namespace teachos::arch::context_switching::descriptor_table
diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp
index 472aed5..d3938ed 100644
--- a/arch/x86_64/src/kernel/main.cpp
+++ b/arch/x86_64/src/kernel/main.cpp
@@ -1,9 +1,11 @@
#include "arch/kernel/main.hpp"
+#include "arch/context_switching/descriptor_table/segment_descriptor.hpp"
#include "arch/memory/heap/bump_allocator.hpp"
#include "arch/memory/heap/global_heap_allocator.hpp"
#include "arch/memory/main.hpp"
#include "arch/memory/multiboot/reader.hpp"
+#include "arch/stl/vector.hpp"
#include "arch/video/vga/text.hpp"
namespace teachos::arch::kernel
@@ -57,5 +59,53 @@ namespace teachos::arch::kernel
memory::heap::global_heap_allocator::register_heap_allocator(memory::heap::heap_allocator_type::LINKED_LIST);
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<segment_descriptor> global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment,
+ user_code_segment, user_data_segment};
+
+ decltype(auto) x = global_descriptor_table.at(1);
+ if (global_descriptor_table.size() == 0)
+ {
+ }
+ if (x.get_segment_type() == segment_descriptor_type::CODE_SEGMENT)
+ {
+ }
+ video::vga::text::write("GDT FILLED", video::vga::text::common_attributes::green_on_black);
}
} // namespace teachos::arch::kernel