From 8d14c729c43ee555c240a043e3909617e4fa5043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 27 Feb 2025 09:24:17 +0000 Subject: Add files to cmake and implement gdt flags --- arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp (limited to 'arch/x86_64/src') 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 new file mode 100644 index 0000000..8a05956 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp @@ -0,0 +1,6 @@ +#include "arch/context_switching/descriptor_table/gdt_flags.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool { return (flags & other) == other; } +} // namespace teachos::arch::context_switching::descriptor_table -- cgit v1.2.3 From d8a8efe3e8d90ec83069d1c934ff319626e87a2d Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 27 Feb 2025 10:13:35 +0000 Subject: add descriptor_table access_byte --- arch/x86_64/src/boot/boot.s | 4 ++-- .../src/context_switching/descriptor_table/access_byte.cpp | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 2197dce..dbea42a 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -197,10 +197,10 @@ _start: call enable_paging call enable_sse - cli // Clears the interrupt flag during the GDT setup + cli /* Clears the interrupt flag during the GDT setup */ lgdt (global_descriptor_table_pointer) jmp $global_descriptor_table_code,$_transition_to_long_mode - // The interrupt flag is set in cpp after setting up the GDT + /* 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/access_byte.cpp b/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp new file mode 100644 index 0000000..15a0947 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp @@ -0,0 +1,14 @@ +#include "arch/context_switching/descriptor_table/access_byte.hpp" + +#include + +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 + { + constexpr uint8_t PRIVILEGE_MASK = 0b0110'0000; + return static_cast(flags.to_ulong() & PRIVILEGE_MASK); + } +} // namespace teachos::arch::context_switching::descriptor_table -- cgit v1.2.3 From 051307f49f4cdfb86c527a475ab21feea4a664d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 4 Mar 2025 18:01:49 +0000 Subject: Add more methods to vector to mimic stl interface partially. --- arch/x86_64/src/memory/main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index a6f91d9..08308db 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -7,6 +7,9 @@ #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" +#include "arch/stl/shared_pointer.hpp" +#include "arch/stl/unique_pointer.hpp" +#include "arch/stl/vector.hpp" namespace teachos::arch::memory { @@ -49,5 +52,11 @@ namespace teachos::arch::memory remap_heap(allocator, active_table); video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); + + auto test2 = stl::make_unique(0); + auto test3 = stl::make_shared(0); + if (test2 && test3) + { + } } } // namespace teachos::arch::memory -- cgit v1.2.3 From 06d5e5872838bd1528493b62b4dc28d44b54aa47 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 9 Mar 2025 09:30:01 +0000 Subject: add doxygen comments to shared and unique pointer --- arch/x86_64/src/memory/main.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 08308db..15e89c0 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -52,11 +52,5 @@ namespace teachos::arch::memory remap_heap(allocator, active_table); video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); - - auto test2 = stl::make_unique(0); - auto test3 = stl::make_shared(0); - if (test2 && test3) - { - } } -} // namespace teachos::arch::memory +} // namespace teachos::arch::memory \ No newline at end of file -- cgit v1.2.3 From 1a6d41362447531a2ea5ee344c15b9aaa6c2090a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 9 Mar 2025 16:52:17 +0000 Subject: Adjust comments and implement remaining interface for STL classes. --- arch/x86_64/src/memory/main.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 15e89c0..a6f91d9 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -7,9 +7,6 @@ #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" -#include "arch/stl/shared_pointer.hpp" -#include "arch/stl/unique_pointer.hpp" -#include "arch/stl/vector.hpp" namespace teachos::arch::memory { @@ -53,4 +50,4 @@ namespace teachos::arch::memory video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); } -} // namespace teachos::arch::memory \ No newline at end of file +} // namespace teachos::arch::memory -- cgit v1.2.3 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.cpp | 15 +++++++------- .../descriptor_table/gdt_flags.cpp | 24 +++++++++++++++++++++- .../descriptor_table/type_field.cpp | 12 +++++++++++ 3 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 arch/x86_64/src/context_switching/descriptor_table/type_field.cpp (limited to 'arch/x86_64/src') 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 - 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(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 -- cgit v1.2.3 From 52fffdf2c76def4a875e0328eb45d74c6e97e805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 10 Mar 2025 16:05:31 +0000 Subject: Adjust segment descriptor to use defined helpers --- .../descriptor_table/segment_descriptor.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp (limited to 'arch/x86_64/src') 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 new file mode 100644 index 0000000..fb9c034 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp @@ -0,0 +1,13 @@ +#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + segment_descriptor::segment_descriptor(uint128_t flags) + : _reserved(flags) + , _access(flags) + , _flag(flags, segment_descriptor_type::SYSTEM_SEGMENT) + , _base(flags) + , _limit(flags) + { + } +} // namespace teachos::arch::context_switching::descriptor_table -- cgit v1.2.3 From 569cf73d1fa14ec11afbb37464d2c356d55d64b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 10 Mar 2025 16:35:01 +0000 Subject: Implement segment descriptor --- .../descriptor_table/gdt_flags.cpp | 18 ++---------------- .../descriptor_table/segment_descriptor.cpp | 21 ++++++++++++++++----- 2 files changed, 18 insertions(+), 21 deletions(-) (limited to 'arch/x86_64/src') 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 8e1e939..8fbf869 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 @@ -4,24 +4,10 @@ namespace teachos::arch::context_switching::descriptor_table { - gdt_flags::gdt_flags(uint8_t flags, segment_descriptor_type type) + gdt_flags::gdt_flags(uint8_t flags) : _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; - } + // Nothing to do. } auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool { return (_flags & other) == other; } 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 fb9c034..57564f2 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 @@ -3,11 +3,22 @@ namespace teachos::arch::context_switching::descriptor_table { segment_descriptor::segment_descriptor(uint128_t flags) - : _reserved(flags) - , _access(flags) - , _flag(flags, segment_descriptor_type::SYSTEM_SEGMENT) - , _base(flags) - , _limit(flags) + : _reserved(flags >> 96U) + , _access((flags >> 40U) << 80U) + , _flag((flags >> 52U) << 72U) + , _base(((flags >> 64U) << 32U) << 32U | ((flags >> 56U) << 64U) << 24U | (flags >> 16U) << 88U) + , _limit(((flags >> 48U) << 72U) << 16U | flags << 112U) { + // 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; } } // namespace teachos::arch::context_switching::descriptor_table -- cgit v1.2.3 From b8a0024ee71a64ec0e87a1e2d0c0c7280dc954e6 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 13 Mar 2025 09:36:00 +0000 Subject: create GDT and fix segment descriptor bit order --- .../descriptor_table/access_byte.cpp | 4 +- .../descriptor_table/gdt_flags.cpp | 2 +- .../descriptor_table/segment_descriptor.cpp | 22 ++++++++-- arch/x86_64/src/kernel/main.cpp | 50 ++++++++++++++++++++++ 4 files changed, 72 insertions(+), 6 deletions(-) (limited to 'arch/x86_64/src') 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 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 -- cgit v1.2.3 From 34c36096e55ac678e29c58f7336b419647e805b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 13 Mar 2025 10:00:42 +0000 Subject: Fix segment descriptor bit order of private members --- .../descriptor_table/segment_descriptor.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'arch/x86_64/src') 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 ab8eaba..a743ad2 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 @@ -3,22 +3,26 @@ namespace teachos::arch::context_switching::descriptor_table { segment_descriptor::segment_descriptor(uint128_t flags) - : _reserved(flags >> 96U) + : _limit_1(flags << 112U) + , _base_1((flags >> 16U) << 88U) , _access((flags >> 44U) << 80U, (flags >> 40U) << 84U) + , _limit_2((flags >> 48U) << 72U) , _flag((flags >> 52U) << 72U) - , _base(((flags >> 64U) << 32U) << 32U | ((flags >> 56U) << 64U) << 24U | (flags >> 16U) << 88U) - , _limit(((flags >> 48U) << 72U) << 16U | flags << 112U) + , _base_2((flags >> 56U) << 32U) + , _reserved(flags >> 96U) { // Nothing to do. } segment_descriptor::segment_descriptor(access_byte access_byte, gdt_flags flags, uint64_t base, std::bitset<20U> limit) - : _reserved(0U) + : _limit_1((limit.to_ulong() << 4U) >> 16U) + , _base_1((base << 40U) >> 40U) , _access(access_byte) + , _limit_2(limit.to_ulong() >> 16U) , _flag(flags) - , _base(base) - , _limit(limit) + , _base_2(base >> 24U) + , _reserved(0U) { // Nothing to do } -- cgit v1.2.3 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/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 +- 11 files changed, 216 insertions(+), 162 deletions(-) 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 (limited to 'arch/x86_64/src') 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 From 11db9338dac611ea32e202add5ce5055b54ebb58 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 13 Mar 2025 15:46:16 +0000 Subject: fixup typing and continue adding gdt --- .../descriptor_table/global_descriptor_table.cpp | 17 ++++++++--------- arch/x86_64/src/kernel/cpu/control_register.cpp | 4 ++-- arch/x86_64/src/kernel/cpu/lgdt.cpp | 14 ++++++++++++++ arch/x86_64/src/kernel/cpu/msr.cpp | 4 ++-- arch/x86_64/src/kernel/cpu/ss.cpp | 8 ++++---- arch/x86_64/src/kernel/cpu/tlb.cpp | 6 +++--- arch/x86_64/src/memory/main.cpp | 4 ++-- 7 files changed, 35 insertions(+), 22 deletions(-) create mode 100644 arch/x86_64/src/kernel/cpu/lgdt.cpp (limited to 'arch/x86_64/src') 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 index 1cba13c..ca3d7ff 100644 --- 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 @@ -1,9 +1,9 @@ -#include "global_descriptor_table.hpp" +#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" +#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" +#include "arch/kernel/cpu/lgdt.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 @@ -43,15 +43,14 @@ namespace teachos::arch::context_switching::descriptor_table 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()}; + + // TODO: Second argument does not work yet (because pointer hpp) global_descriptor_table_pointer gdt_pointer{gdt.size() - 1, &gdt}; - load_global_descriptor_table(gdt_pointer); + kernel::cpu::load_global_descriptor_table(gdt_pointer); + + return gdt; } } // 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 index 3051bae..a39a360 100644 --- a/arch/x86_64/src/kernel/cpu/control_register.cpp +++ b/arch/x86_64/src/kernel/cpu/control_register.cpp @@ -4,7 +4,7 @@ #include -namespace teachos::arch::memory::cpu +namespace teachos::arch::kernel::cpu { auto read_control_register(control_register cr) -> uint64_t { @@ -69,4 +69,4 @@ namespace teachos::arch::memory::cpu 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 +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/lgdt.cpp b/arch/x86_64/src/kernel/cpu/lgdt.cpp new file mode 100644 index 0000000..cb13aa8 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/lgdt.cpp @@ -0,0 +1,14 @@ +#include "arch/kernel/cpu/lgdt.hpp" + +#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer gdt_pointer) + -> void + { + // TODO: build lgdt argument from global_descriptor_table_pointer (don't know how yet) + asm volatile("lgdt (%0)" : : "r"(gdt_pointer)); + } + +} // namespace teachos::arch::kernel::cpu \ No newline at end of file diff --git a/arch/x86_64/src/kernel/cpu/msr.cpp b/arch/x86_64/src/kernel/cpu/msr.cpp index 082bca9..6249f8f 100644 --- a/arch/x86_64/src/kernel/cpu/msr.cpp +++ b/arch/x86_64/src/kernel/cpu/msr.cpp @@ -1,6 +1,6 @@ #include "arch/kernel/cpu/msr.hpp" -namespace teachos::arch::memory::cpu +namespace teachos::arch::kernel::cpu { namespace { @@ -28,4 +28,4 @@ namespace teachos::arch::memory::cpu auto const efer = read_msr(IA32_EFER_ADDRESS); write_msr(IA32_EFER_ADDRESS, static_cast::type>(flag) | efer); } -} // namespace teachos::arch::memory::cpu +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/ss.cpp b/arch/x86_64/src/kernel/cpu/ss.cpp index b7e52e1..9c8dd61 100644 --- a/arch/x86_64/src/kernel/cpu/ss.cpp +++ b/arch/x86_64/src/kernel/cpu/ss.cpp @@ -1,6 +1,6 @@ #include "arch/kernel/cpu/ss.hpp" -namespace teachos::arch::memory::cpu +namespace teachos::arch::kernel::cpu { segment_selector::segment_selector(uint16_t index, std::bitset<1U> table_indicator, std::bitset<2U> requested_privilege_level) @@ -20,14 +20,14 @@ namespace teachos::arch::memory::cpu auto read_ss() -> uint16_t { uint16_t ss; - __asm__("mov %%ss, %0" : "=r"(ss)); + asm volatile("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)); + asm volatile("mov %0, %%ss" ::"r"(ss)); } -} // namespace teachos::arch::memory::cpu \ No newline at end of file +} // namespace teachos::arch::kernel::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 index e753c2c..a09001c 100644 --- a/arch/x86_64/src/kernel/cpu/tlb.cpp +++ b/arch/x86_64/src/kernel/cpu/tlb.cpp @@ -2,9 +2,9 @@ #include "arch/kernel/cpu/control_register.hpp" -namespace teachos::arch::memory::cpu +namespace teachos::arch::kernel::cpu { - auto tlb_flush(paging::virtual_address address) -> void + auto tlb_flush(memory::paging::virtual_address address) -> void { asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); } @@ -13,4 +13,4 @@ namespace teachos::arch::memory::cpu { write_control_register(cpu::control_register::CR3, read_control_register(cpu::control_register::CR3)); } -} // namespace teachos::arch::memory::cpu +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index abc7431..a920a20 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -38,8 +38,8 @@ namespace teachos::arch::memory auto const memory_information = multiboot::read_multiboot2(); allocator::area_frame_allocator allocator(memory_information); - cpu::set_cr0_bit(memory::cpu::cr0_flags::WRITE_PROTECT); - cpu::set_efer_bit(memory::cpu::efer_flags::NXE); + kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); paging::kernel_mapper kernel(allocator, memory_information); auto & active_table = kernel.remap_kernel(); -- cgit v1.2.3 From f2b9ac8f0f22354241e9b78e47aa7cb94e5ef511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 14 Mar 2025 14:20:24 +0000 Subject: Fix header recursion problem --- .../descriptor_table/global_descriptor_table.cpp | 7 ++----- arch/x86_64/src/kernel/cpu/lgdt.cpp | 11 +++++++---- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'arch/x86_64/src') 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 index ca3d7ff..f4ea61b 100644 --- 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 @@ -45,12 +45,9 @@ namespace teachos::arch::context_switching::descriptor_table auto initialize_global_descriptor_table() -> global_descriptor_table { - global_descriptor_table gdt{create_global_descriptor_table()}; - - // TODO: Second argument does not work yet (because pointer hpp) + decltype(auto) gdt = create_global_descriptor_table(); global_descriptor_table_pointer gdt_pointer{gdt.size() - 1, &gdt}; kernel::cpu::load_global_descriptor_table(gdt_pointer); - return gdt; } -} // namespace teachos::arch::context_switching::descriptor_table \ No newline at end of file +} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/lgdt.cpp b/arch/x86_64/src/kernel/cpu/lgdt.cpp index cb13aa8..70a48dd 100644 --- a/arch/x86_64/src/kernel/cpu/lgdt.cpp +++ b/arch/x86_64/src/kernel/cpu/lgdt.cpp @@ -4,11 +4,14 @@ namespace teachos::arch::kernel::cpu { - auto load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer gdt_pointer) + auto + load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer const & gdt_pointer) -> void { // TODO: build lgdt argument from global_descriptor_table_pointer (don't know how yet) - asm volatile("lgdt (%0)" : : "r"(gdt_pointer)); + // asm volatile("lgdt (%0)" : : "r"(gdt_pointer)); + if (gdt_pointer.table_length) + { + } } - -} // namespace teachos::arch::kernel::cpu \ No newline at end of file +} // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 2b8e6e7e10f084a9a9ba5c0b79a041f4d1ac459b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 15 Mar 2025 11:29:26 +0000 Subject: implement loading of gdtr register --- .../descriptor_table/access_byte.cpp | 10 +++--- .../descriptor_table/gdt_flags.cpp | 14 +++++--- .../descriptor_table/global_descriptor_table.cpp | 40 +++++++++++++--------- .../global_descriptor_table_pointer.cpp | 12 +++++++ .../descriptor_table/segment_descriptor.cpp | 17 +++------ .../descriptor_table/type_field.cpp | 12 ------- arch/x86_64/src/kernel/cpu/lgdt.cpp | 13 ++++--- arch/x86_64/src/kernel/cpu/ss.cpp | 8 ++--- arch/x86_64/src/kernel/main.cpp | 13 ++----- .../src/memory/heap/linked_list_allocator.cpp | 2 +- arch/x86_64/src/shared/mutex.cpp | 16 --------- arch/x86_64/src/stl/mutex.cpp | 16 +++++++++ 12 files changed, 86 insertions(+), 87 deletions(-) create mode 100644 arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/type_field.cpp delete mode 100644 arch/x86_64/src/shared/mutex.cpp create mode 100644 arch/x86_64/src/stl/mutex.cpp (limited to 'arch/x86_64/src') 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 4e5459f..6b54451 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,14 +2,14 @@ namespace teachos::arch::context_switching::descriptor_table { - access_byte::access_byte(uint8_t flags, uint8_t type_field) + access_byte::access_byte(uint8_t flags) : _flags(flags) - , _type(type_field) { // 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; } + auto access_byte::contains_flags(std::bitset<8U> other) const -> bool + { + return (std::bitset<8U>{_flags} & other) == other; + } } // 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 65f2e90..9e95182 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,14 +1,18 @@ #include "arch/context_switching/descriptor_table/gdt_flags.hpp" -#include "arch/exception_handling/assert.hpp" - namespace teachos::arch::context_switching::descriptor_table { - gdt_flags::gdt_flags(uint8_t flags) - : _flags(flags) + gdt_flags::gdt_flags(uint8_t flags, std::bitset<20U> limit) + : _limit_2(limit.to_ulong() >> 16U) + , _flags(flags) { // Nothing to do. } - auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool { return (_flags & other) == other; } + auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool + { + return (std::bitset<4U>{_flags} & other) == other; + } + + auto descriptor_table::gdt_flags::get_limit() const -> std::bitset<4U> { return std::bitset<4U>{_limit_2}; } } // namespace teachos::arch::context_switching::descriptor_table 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 index f4ea61b..c5554a7 100644 --- 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 @@ -1,6 +1,7 @@ #include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" #include "arch/context_switching/descriptor_table/segment_descriptor.hpp" +#include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/lgdt.hpp" #include "arch/stl/vector.hpp" @@ -10,33 +11,32 @@ namespace teachos::arch::context_switching::descriptor_table { segment_descriptor null_segment{0}; + std::bitset<20U> limit{0xFFFFF}; // 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}; + access_byte::CODE_OR_DATA_SEGMENT | access_byte::CODE_SEGMENT | + access_byte::READABLE}; + gdt_flags kernel_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH, limit}; + segment_descriptor kernel_code_segment{kernel_code_access_byte, kernel_code_gdt_flags, 0, limit}; // 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}; + access_byte::CODE_OR_DATA_SEGMENT | access_byte::WRITABLE}; + gdt_flags kernel_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND, limit}; + segment_descriptor kernel_data_segment{kernel_data_access_byte, kernel_data_gdt_flags, 0, limit}; // 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}; + access_byte::CODE_OR_DATA_SEGMENT | access_byte::CODE_SEGMENT | + access_byte::READABLE}; + gdt_flags user_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH, limit}; + segment_descriptor user_code_segment{user_code_access_byte, user_code_gdt_flags, 0, limit}; // 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}; + access_byte::CODE_OR_DATA_SEGMENT | access_byte::WRITABLE}; + gdt_flags user_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND, limit}; + segment_descriptor user_data_segment{user_data_access_byte, user_data_gdt_flags, 0, limit}; stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, user_code_segment, user_data_segment}; @@ -46,8 +46,14 @@ namespace teachos::arch::context_switching::descriptor_table auto initialize_global_descriptor_table() -> global_descriptor_table { decltype(auto) gdt = create_global_descriptor_table(); - global_descriptor_table_pointer gdt_pointer{gdt.size() - 1, &gdt}; + global_descriptor_table_pointer gdt_pointer{static_cast(gdt.size() - 1), &gdt}; kernel::cpu::load_global_descriptor_table(gdt_pointer); + + auto stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); + arch::exception_handling::assert( + gdt_pointer == stored_gdt_pointer, + "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); + return gdt; } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp new file mode 100644 index 0000000..f552496 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp @@ -0,0 +1,12 @@ +#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, + global_descriptor_table * address) + : table_length(table_length) + , address(address) + { + // Nothing to do. + } +} // namespace teachos::arch::context_switching::descriptor_table 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 a743ad2..c1a46a6 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 @@ -5,9 +5,8 @@ namespace teachos::arch::context_switching::descriptor_table segment_descriptor::segment_descriptor(uint128_t flags) : _limit_1(flags << 112U) , _base_1((flags >> 16U) << 88U) - , _access((flags >> 44U) << 80U, (flags >> 40U) << 84U) - , _limit_2((flags >> 48U) << 72U) - , _flag((flags >> 52U) << 72U) + , _access((flags >> 40U) << 80U) + , _flag((flags >> 52U) << 72U, (flags >> 48U) << 72U) , _base_2((flags >> 56U) << 32U) , _reserved(flags >> 96U) { @@ -16,10 +15,9 @@ namespace teachos::arch::context_switching::descriptor_table segment_descriptor::segment_descriptor(access_byte access_byte, gdt_flags flags, uint64_t base, std::bitset<20U> limit) - : _limit_1((limit.to_ulong() << 4U) >> 16U) + : _limit_1(limit.to_ulong()) , _base_1((base << 40U) >> 40U) , _access(access_byte) - , _limit_2(limit.to_ulong() >> 16U) , _flag(flags) , _base_2(base >> 24U) , _reserved(0U) @@ -33,12 +31,7 @@ namespace teachos::arch::context_switching::descriptor_table { return segment_descriptor_type::SYSTEM_SEGMENT; } - - if (_access.get_type_field().contains_flags(type_field::CODE_SEGMENT)) - { - return segment_descriptor_type::CODE_SEGMENT; - } - - return segment_descriptor_type::DATA_SEGMENT; + return _access.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT + : segment_descriptor_type::DATA_SEGMENT; } } // 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 deleted file mode 100644 index d967a97..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/type_field.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#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 diff --git a/arch/x86_64/src/kernel/cpu/lgdt.cpp b/arch/x86_64/src/kernel/cpu/lgdt.cpp index 70a48dd..386914f 100644 --- a/arch/x86_64/src/kernel/cpu/lgdt.cpp +++ b/arch/x86_64/src/kernel/cpu/lgdt.cpp @@ -4,14 +4,17 @@ namespace teachos::arch::kernel::cpu { + auto store_global_descriptor_table() -> context_switching::descriptor_table::global_descriptor_table_pointer + { + context_switching::descriptor_table::global_descriptor_table_pointer current_value{}; + asm("sgdt %[output]" : [output] "=m"(current_value)); + return current_value; + } + auto load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer const & gdt_pointer) -> void { - // TODO: build lgdt argument from global_descriptor_table_pointer (don't know how yet) - // asm volatile("lgdt (%0)" : : "r"(gdt_pointer)); - if (gdt_pointer.table_length) - { - } + asm volatile("lgdt %[input]" : /* no output from call */ : [input] "m"(gdt_pointer)); } } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/ss.cpp b/arch/x86_64/src/kernel/cpu/ss.cpp index 9c8dd61..1f28e7f 100644 --- a/arch/x86_64/src/kernel/cpu/ss.cpp +++ b/arch/x86_64/src/kernel/cpu/ss.cpp @@ -19,15 +19,15 @@ namespace teachos::arch::kernel::cpu auto read_ss() -> uint16_t { - uint16_t ss; - asm volatile("mov %%ss, %0" : "=r"(ss)); - return ss; + uint16_t segment_selector; + asm volatile("mov %%ss, %[output]" : [output] "=r"(segment_selector)); + return segment_selector; } auto write_ss(segment_selector selector) -> void { uint16_t ss = selector.to_uint16(); - asm volatile("mov %0, %%ss" ::"r"(ss)); + asm volatile("mov %[input], %%ss" : /* no output from call */ : [input] "r"(ss)); } } // namespace teachos::arch::kernel::cpu \ No newline at end of file diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 4db9599..2c0b6c8 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,6 +1,7 @@ #include "arch/kernel/main.hpp" #include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" +#include "arch/kernel/cpu/lgdt.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/main.hpp" @@ -60,16 +61,8 @@ namespace teachos::arch::kernel heap_test(); - 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() == context_switching::descriptor_table::segment_descriptor_type::CODE_SEGMENT) - { - } + auto global_descriptor_table = context_switching::descriptor_table::initialize_global_descriptor_table(); + (void)global_descriptor_table.at(1); video::vga::text::write("GDT FILLED", video::vga::text::common_attributes::green_on_black); } } // namespace teachos::arch::kernel diff --git a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp index a824c8a..5101ab2 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -11,7 +11,7 @@ namespace teachos::arch::memory::heap : heap_start(heap_start) , heap_end(heap_end) , first(nullptr) - , mutex{shared::mutex{}} + , mutex{stl::mutex{}} { auto const heap_size = heap_end - heap_start; exception_handling::assert( diff --git a/arch/x86_64/src/shared/mutex.cpp b/arch/x86_64/src/shared/mutex.cpp deleted file mode 100644 index 6598255..0000000 --- a/arch/x86_64/src/shared/mutex.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "arch/shared/mutex.hpp" - -namespace teachos::arch::shared -{ - auto mutex::lock() -> void - { - while (!try_lock()) - { - // Nothing to do - } - } - - auto mutex::try_lock() -> bool { return !locked.exchange(true, std::memory_order_acquire); } - - auto mutex::unlock() -> void { locked.store(false, std::memory_order_release); } -} // namespace teachos::arch::shared diff --git a/arch/x86_64/src/stl/mutex.cpp b/arch/x86_64/src/stl/mutex.cpp new file mode 100644 index 0000000..232a11c --- /dev/null +++ b/arch/x86_64/src/stl/mutex.cpp @@ -0,0 +1,16 @@ +#include "arch/stl/mutex.hpp" + +namespace teachos::arch::stl +{ + auto mutex::lock() -> void + { + while (!try_lock()) + { + // Nothing to do + } + } + + auto mutex::try_lock() -> bool { return !locked.exchange(true, std::memory_order_acquire); } + + auto mutex::unlock() -> void { locked.store(false, std::memory_order_release); } +} // namespace teachos::arch::stl -- cgit v1.2.3 From e6a9d939ed5e9f89e69efdacc60a1ce6edd1061c Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 15 Mar 2025 12:38:11 +0000 Subject: temporarily make all page table entries user accessible --- arch/x86_64/src/memory/paging/page_entry.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 5aa0982..3a0f03f 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -10,7 +10,7 @@ namespace teachos::arch::memory::paging } // namespace entry::entry(uint64_t flags) - : flags(flags) + : flags(flags | entry::USER_ACCESSIBLE) // TODO: Temporarily make all entries user accessible { // Nothing to do. } @@ -21,14 +21,19 @@ namespace teachos::arch::memory::paging { flags |= entry::PRESENT; } + if (elf_flags.contains_flags(multiboot::elf_section_flags::WRITABLE)) { flags |= entry::WRITABLE; } + if (!elf_flags.contains_flags(multiboot::elf_section_flags::EXECUTABLE_CODE)) { flags |= entry::EXECUTING_CODE_FORBIDDEN; } + + // TODO: Temporarily make all entries user accessible + flags |= entry::USER_ACCESSIBLE; } auto entry::is_unused() const -> bool { return flags == 0U; } @@ -51,7 +56,9 @@ namespace teachos::arch::memory::paging { exception_handling::assert((frame.start_address() & ~PHYSICAL_ADDRESS_MASK) == 0, "[Paging Entry] Start address is not aligned with page"); - flags = frame.start_address() | additional_flags.to_ulong(); + + // TODO: Temporarily make all entries user accessible + flags = frame.start_address() | additional_flags.to_ulong() | entry::USER_ACCESSIBLE; } auto entry::get_flags() const -> std::bitset<64U> { return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; } -- cgit v1.2.3 From 5a332c90f79e6d10de1a8cd478c4dbef82f4d74d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 15 Mar 2025 14:48:29 +0000 Subject: Use empty bit field to implement reserved --- .../src/context_switching/descriptor_table/segment_descriptor.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch/x86_64/src') 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 c1a46a6..3e93823 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 @@ -8,7 +8,6 @@ namespace teachos::arch::context_switching::descriptor_table , _access((flags >> 40U) << 80U) , _flag((flags >> 52U) << 72U, (flags >> 48U) << 72U) , _base_2((flags >> 56U) << 32U) - , _reserved(flags >> 96U) { // Nothing to do. } @@ -20,7 +19,6 @@ namespace teachos::arch::context_switching::descriptor_table , _access(access_byte) , _flag(flags) , _base_2(base >> 24U) - , _reserved(0U) { // Nothing to do } -- cgit v1.2.3 From ecb67842d3578dfc8c7d685b0cd168efd24505e6 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 15 Mar 2025 14:56:12 +0000 Subject: create TSS descriptor --- .../descriptor_table/global_descriptor_table.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'arch/x86_64/src') 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 index c5554a7..6474739 100644 --- 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 @@ -12,6 +12,7 @@ namespace teachos::arch::context_switching::descriptor_table segment_descriptor null_segment{0}; std::bitset<20U> limit{0xFFFFF}; + // Kernel space code segment access_byte kernel_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | access_byte::CODE_OR_DATA_SEGMENT | access_byte::CODE_SEGMENT | @@ -38,6 +39,15 @@ namespace teachos::arch::context_switching::descriptor_table gdt_flags user_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND, limit}; segment_descriptor user_data_segment{user_data_access_byte, user_data_gdt_flags, 0, limit}; + // Task state segment + // TODO: Create TSS + access_byte tss_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | + access_byte::TASK_STATE_SEGMENT_AVAILABLE}; + gdt_flags tss_gdt_flags{0U, limit}; + uint64_t tss_address = 0; // &TSS + uint64_t tss_limit = 0U; // sizeof(TSS) - 1 + segment_descriptor task_state_segment{tss_access_byte, tss_gdt_flags, tss_address, tss_limit}; + stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, user_code_segment, user_data_segment}; return global_descriptor_table; -- cgit v1.2.3 From 36758071881088b27a52cee4e5653f6cf6a79a78 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 16 Mar 2025 12:41:09 +0000 Subject: start implementing TSS --- .../descriptor_table/global_descriptor_table.cpp | 108 ++++++++++++++------- arch/x86_64/src/kernel/cpu/gdtr.cpp | 20 ++++ arch/x86_64/src/kernel/cpu/lgdt.cpp | 20 ---- arch/x86_64/src/kernel/cpu/tr.cpp | 17 ++++ arch/x86_64/src/kernel/main.cpp | 1 - 5 files changed, 108 insertions(+), 58 deletions(-) create mode 100644 arch/x86_64/src/kernel/cpu/gdtr.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/lgdt.cpp create mode 100644 arch/x86_64/src/kernel/cpu/tr.cpp (limited to 'arch/x86_64/src') 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 index 6474739..2b399f8 100644 --- 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 @@ -1,61 +1,87 @@ #include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" #include "arch/context_switching/descriptor_table/segment_descriptor.hpp" +#include "arch/context_switching/descriptor_table/task_state_segment.hpp" #include "arch/exception_handling/assert.hpp" -#include "arch/kernel/cpu/lgdt.hpp" +#include "arch/kernel/cpu/gdtr.hpp" +#include "arch/kernel/cpu/tr.hpp" #include "arch/stl/vector.hpp" namespace teachos::arch::context_switching::descriptor_table { + auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_level access_level) + -> segment_descriptor + { + uint8_t access_level_bitset = access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT; + if (access_level == access_level::KERNEL) + { + access_level_bitset |= access_byte::ACCESS_LEVEL_KERNEL; + } + else if (access_level == access_level::USER) + { + access_level_bitset = access_byte::ACCESS_LEVEL_USER; + } + + uint8_t gdt_flags_bitset = gdt_flags::GRANULARITY; + if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) + { + gdt_flags_bitset |= gdt_flags::LENGTH; + access_level_bitset |= access_byte::CODE_SEGMENT | access_byte::READABLE; + } + else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) + { + gdt_flags_bitset |= gdt_flags::UPPER_BOUND; + access_level_bitset |= access_byte::WRITABLE; + } + + std::bitset<20U> limit{0xFFFFF}; + access_byte access_byte{access_level_bitset}; + gdt_flags gdt_flags{gdt_flags_bitset, limit}; + segment_descriptor code_segment{access_byte, gdt_flags, 0, limit}; + + return code_segment; + } + auto create_global_descriptor_table() -> global_descriptor_table { segment_descriptor null_segment{0}; + segment_descriptor kernel_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::KERNEL); + segment_descriptor kernel_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::KERNEL); + segment_descriptor user_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::USER); + segment_descriptor user_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); - std::bitset<20U> limit{0xFFFFF}; + stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment}; + return global_descriptor_table; + } - // Kernel space code segment - access_byte kernel_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | - access_byte::CODE_OR_DATA_SEGMENT | access_byte::CODE_SEGMENT | - access_byte::READABLE}; - gdt_flags kernel_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH, limit}; - segment_descriptor kernel_code_segment{kernel_code_access_byte, kernel_code_gdt_flags, 0, limit}; - - // Kernel space data segment - access_byte kernel_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | - access_byte::CODE_OR_DATA_SEGMENT | access_byte::WRITABLE}; - gdt_flags kernel_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND, limit}; - segment_descriptor kernel_data_segment{kernel_data_access_byte, kernel_data_gdt_flags, 0, limit}; - - // User space code segment - access_byte user_code_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | - access_byte::CODE_OR_DATA_SEGMENT | access_byte::CODE_SEGMENT | - access_byte::READABLE}; - gdt_flags user_code_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::LENGTH, limit}; - segment_descriptor user_code_segment{user_code_access_byte, user_code_gdt_flags, 0, limit}; - - // User space data segment - access_byte user_data_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_USER | - access_byte::CODE_OR_DATA_SEGMENT | access_byte::WRITABLE}; - gdt_flags user_data_gdt_flags{gdt_flags::GRANULARITY | gdt_flags::UPPER_BOUND, limit}; - segment_descriptor user_data_segment{user_data_access_byte, user_data_gdt_flags, 0, limit}; - - // Task state segment - // TODO: Create TSS + auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor + { + std::bitset<20U> limit{0xFFFFF}; access_byte tss_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | access_byte::TASK_STATE_SEGMENT_AVAILABLE}; gdt_flags tss_gdt_flags{0U, limit}; - uint64_t tss_address = 0; // &TSS - uint64_t tss_limit = 0U; // sizeof(TSS) - 1 - segment_descriptor task_state_segment{tss_access_byte, tss_gdt_flags, tss_address, tss_limit}; + uint64_t tss_address = reinterpret_cast(tss); + constexpr uint64_t tss_limit = sizeof(task_state_segment) - 1; + segment_descriptor tss_descriptor{tss_access_byte, tss_gdt_flags, tss_address, tss_limit}; - stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment}; - return global_descriptor_table; + return tss_descriptor; } auto initialize_global_descriptor_table() -> global_descriptor_table { - decltype(auto) gdt = create_global_descriptor_table(); + auto gdt = create_global_descriptor_table(); + + // Add TSS segment descriptor to GDT + auto tss = new task_state_segment(); + auto tss_descriptor = create_task_state_segment_descriptor(tss); + gdt.push_back(tss_descriptor); + + // Load GDT into GDTR global_descriptor_table_pointer gdt_pointer{static_cast(gdt.size() - 1), &gdt}; kernel::cpu::load_global_descriptor_table(gdt_pointer); @@ -64,6 +90,14 @@ namespace teachos::arch::context_switching::descriptor_table gdt_pointer == stored_gdt_pointer, "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); + // Load Task Register (LTR) using the index of TSS descriptor + uint16_t tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor); + kernel::cpu::load_task_register(tss_selector); + + auto stored_task_register = kernel::cpu::store_task_register(); + arch::exception_handling::assert(tss_selector == stored_task_register, + "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); + return gdt; } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/gdtr.cpp b/arch/x86_64/src/kernel/cpu/gdtr.cpp new file mode 100644 index 0000000..2fe3a99 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/gdtr.cpp @@ -0,0 +1,20 @@ +#include "arch/kernel/cpu/gdtr.hpp" + +#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto store_global_descriptor_table() -> context_switching::descriptor_table::global_descriptor_table_pointer + { + context_switching::descriptor_table::global_descriptor_table_pointer current_value{}; + asm("sgdt %[output]" : [output] "=m"(current_value)); + return current_value; + } + + auto + load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer const & gdt_pointer) + -> void + { + asm volatile("lgdt %[input]" : /* no output from call */ : [input] "m"(gdt_pointer)); + } +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/lgdt.cpp b/arch/x86_64/src/kernel/cpu/lgdt.cpp deleted file mode 100644 index 386914f..0000000 --- a/arch/x86_64/src/kernel/cpu/lgdt.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "arch/kernel/cpu/lgdt.hpp" - -#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto store_global_descriptor_table() -> context_switching::descriptor_table::global_descriptor_table_pointer - { - context_switching::descriptor_table::global_descriptor_table_pointer current_value{}; - asm("sgdt %[output]" : [output] "=m"(current_value)); - return current_value; - } - - auto - load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer const & gdt_pointer) - -> void - { - asm volatile("lgdt %[input]" : /* no output from call */ : [input] "m"(gdt_pointer)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/tr.cpp b/arch/x86_64/src/kernel/cpu/tr.cpp new file mode 100644 index 0000000..a28b9fc --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/tr.cpp @@ -0,0 +1,17 @@ +#include "arch/kernel/cpu/tr.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto store_task_register() -> uint16_t + { + uint16_t current_value{}; + asm("str %[output]" : [output] "=m"(current_value)); + return current_value; + } + + // TODO: Is this really correct? + auto load_task_register(uint16_t gdt_offset) -> void + { + asm volatile("ltr %[input]" : /* no output from call */ : [input] "m"(gdt_offset)); + } +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 2c0b6c8..c1e134a 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,7 +1,6 @@ #include "arch/kernel/main.hpp" #include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" -#include "arch/kernel/cpu/lgdt.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/main.hpp" -- cgit v1.2.3 From 37cb71ca7771a28835e3ed6aa5ed0797c9ba50fa Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 16 Mar 2025 12:50:14 +0000 Subject: add comment --- arch/x86_64/src/kernel/cpu/tr.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kernel/cpu/tr.cpp b/arch/x86_64/src/kernel/cpu/tr.cpp index a28b9fc..ad38d09 100644 --- a/arch/x86_64/src/kernel/cpu/tr.cpp +++ b/arch/x86_64/src/kernel/cpu/tr.cpp @@ -9,7 +9,6 @@ namespace teachos::arch::kernel::cpu return current_value; } - // TODO: Is this really correct? auto load_task_register(uint16_t gdt_offset) -> void { asm volatile("ltr %[input]" : /* no output from call */ : [input] "m"(gdt_offset)); -- cgit v1.2.3 From 5d1fbaba03f411b93281ef6934166d897cd0713e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 16 Mar 2025 13:42:44 +0000 Subject: Move base value out into variable --- .../context_switching/descriptor_table/global_descriptor_table.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src') 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 index 2b399f8..77bd3e9 100644 --- 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 @@ -34,10 +34,11 @@ namespace teachos::arch::context_switching::descriptor_table access_level_bitset |= access_byte::WRITABLE; } + uint64_t base = 0x0; std::bitset<20U> limit{0xFFFFF}; access_byte access_byte{access_level_bitset}; gdt_flags gdt_flags{gdt_flags_bitset, limit}; - segment_descriptor code_segment{access_byte, gdt_flags, 0, limit}; + segment_descriptor code_segment{access_byte, gdt_flags, base, limit}; return code_segment; } @@ -54,8 +55,8 @@ namespace teachos::arch::context_switching::descriptor_table segment_descriptor user_data_segment = create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); - stl::vector global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment}; + global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment}; return global_descriptor_table; } -- cgit v1.2.3 From c56a8a74bc4e9662469db33a85c12586f202985a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 17 Mar 2025 09:38:39 +0000 Subject: Fix issue in vector --- .../descriptor_table/global_descriptor_table.cpp | 27 ++++++++++------------ arch/x86_64/src/kernel/cpu/tr.cpp | 4 ++-- arch/x86_64/src/kernel/main.cpp | 2 +- 3 files changed, 15 insertions(+), 18 deletions(-) (limited to 'arch/x86_64/src') 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 index 77bd3e9..21a76e8 100644 --- 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 @@ -54,9 +54,12 @@ namespace teachos::arch::context_switching::descriptor_table create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::USER); segment_descriptor user_data_segment = create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); + // Task State Segment needs to be kept alive + static auto tss = new task_state_segment(); + segment_descriptor tss_descriptor = create_task_state_segment_descriptor(tss); - global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment}; + global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment, tss_descriptor}; return global_descriptor_table; } @@ -67,20 +70,15 @@ namespace teachos::arch::context_switching::descriptor_table access_byte::TASK_STATE_SEGMENT_AVAILABLE}; gdt_flags tss_gdt_flags{0U, limit}; uint64_t tss_address = reinterpret_cast(tss); - constexpr uint64_t tss_limit = sizeof(task_state_segment) - 1; - segment_descriptor tss_descriptor{tss_access_byte, tss_gdt_flags, tss_address, tss_limit}; - + constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; + segment_descriptor tss_descriptor{tss_access_byte, tss_gdt_flags, tss_address, TSS_LIMIT}; return tss_descriptor; } - auto initialize_global_descriptor_table() -> global_descriptor_table + auto initialize_global_descriptor_table() -> global_descriptor_table & { - auto gdt = create_global_descriptor_table(); - - // Add TSS segment descriptor to GDT - auto tss = new task_state_segment(); - auto tss_descriptor = create_task_state_segment_descriptor(tss); - gdt.push_back(tss_descriptor); + // Global Descriptor Table needs to be kept alive + static auto gdt = create_global_descriptor_table(); // Load GDT into GDTR global_descriptor_table_pointer gdt_pointer{static_cast(gdt.size() - 1), &gdt}; @@ -91,14 +89,13 @@ namespace teachos::arch::context_switching::descriptor_table gdt_pointer == stored_gdt_pointer, "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); - // Load Task Register (LTR) using the index of TSS descriptor - uint16_t tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor); + // Calculate the offset of the gdt in bytes to the TSS descriptor + uint16_t const tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor); kernel::cpu::load_task_register(tss_selector); auto stored_task_register = kernel::cpu::store_task_register(); arch::exception_handling::assert(tss_selector == stored_task_register, "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); - return gdt; } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/tr.cpp b/arch/x86_64/src/kernel/cpu/tr.cpp index ad38d09..d0e037f 100644 --- a/arch/x86_64/src/kernel/cpu/tr.cpp +++ b/arch/x86_64/src/kernel/cpu/tr.cpp @@ -5,12 +5,12 @@ namespace teachos::arch::kernel::cpu auto store_task_register() -> uint16_t { uint16_t current_value{}; - asm("str %[output]" : [output] "=m"(current_value)); + asm("str %[output]" : [output] "=r"(current_value)); return current_value; } auto load_task_register(uint16_t gdt_offset) -> void { - asm volatile("ltr %[input]" : /* no output from call */ : [input] "m"(gdt_offset)); + asm volatile("ltr %[input]" : /* no output from call */ : [input] "r"(gdt_offset)); } } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index c1e134a..da6d6d3 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -60,7 +60,7 @@ namespace teachos::arch::kernel heap_test(); - auto global_descriptor_table = context_switching::descriptor_table::initialize_global_descriptor_table(); + decltype(auto) global_descriptor_table = context_switching::descriptor_table::initialize_global_descriptor_table(); (void)global_descriptor_table.at(1); video::vga::text::write("GDT FILLED", video::vga::text::common_attributes::green_on_black); } -- cgit v1.2.3 From 3c01f820a064f3120a46aa3afdd9f88ce9e00db3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 17 Mar 2025 14:51:24 +0000 Subject: Debug and adjust load task register assembly call. WIP --- .../descriptor_table/global_descriptor_table.cpp | 42 ++++++++++------------ .../descriptor_table/segment_descriptor.cpp | 2 +- arch/x86_64/src/kernel/cpu/tr.cpp | 8 ++++- 3 files changed, 27 insertions(+), 25 deletions(-) (limited to 'arch/x86_64/src') 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 index 21a76e8..b338d9d 100644 --- 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 @@ -34,44 +34,41 @@ namespace teachos::arch::context_switching::descriptor_table access_level_bitset |= access_byte::WRITABLE; } - uint64_t base = 0x0; - std::bitset<20U> limit{0xFFFFF}; - access_byte access_byte{access_level_bitset}; - gdt_flags gdt_flags{gdt_flags_bitset, limit}; - segment_descriptor code_segment{access_byte, gdt_flags, base, limit}; - + uint64_t const base = 0x0; + std::bitset<20U> const limit{0xFFFFF}; + access_byte const access_byte{access_level_bitset}; + gdt_flags const gdt_flags{gdt_flags_bitset, limit}; + segment_descriptor const code_segment{access_byte, gdt_flags, base, limit}; return code_segment; } auto create_global_descriptor_table() -> global_descriptor_table { - segment_descriptor null_segment{0}; - segment_descriptor kernel_code_segment = + segment_descriptor const null_segment{0}; + segment_descriptor const kernel_code_segment = create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::KERNEL); - segment_descriptor kernel_data_segment = + segment_descriptor const kernel_data_segment = create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::KERNEL); - segment_descriptor user_code_segment = + segment_descriptor const user_code_segment = create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::USER); - segment_descriptor user_data_segment = + segment_descriptor const user_data_segment = create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); // Task State Segment needs to be kept alive static auto tss = new task_state_segment(); - segment_descriptor tss_descriptor = create_task_state_segment_descriptor(tss); + segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); - global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment, tss_descriptor}; + global_descriptor_table const global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment, tss_descriptor}; return global_descriptor_table; } auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor { - std::bitset<20U> limit{0xFFFFF}; - access_byte tss_access_byte{access_byte::PRESENT | access_byte::ACCESS_LEVEL_KERNEL | - access_byte::TASK_STATE_SEGMENT_AVAILABLE}; - gdt_flags tss_gdt_flags{0U, limit}; - uint64_t tss_address = reinterpret_cast(tss); constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; - segment_descriptor tss_descriptor{tss_access_byte, tss_gdt_flags, tss_address, TSS_LIMIT}; + access_byte const tss_access_byte{access_byte::PRESENT | access_byte::ACCESS_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(tss), TSS_LIMIT}; return tss_descriptor; } @@ -80,11 +77,10 @@ namespace teachos::arch::context_switching::descriptor_table // Global Descriptor Table needs to be kept alive static auto gdt = create_global_descriptor_table(); - // Load GDT into GDTR global_descriptor_table_pointer gdt_pointer{static_cast(gdt.size() - 1), &gdt}; kernel::cpu::load_global_descriptor_table(gdt_pointer); - auto stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); + auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); arch::exception_handling::assert( gdt_pointer == stored_gdt_pointer, "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); @@ -93,7 +89,7 @@ namespace teachos::arch::context_switching::descriptor_table uint16_t const tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor); kernel::cpu::load_task_register(tss_selector); - auto stored_task_register = kernel::cpu::store_task_register(); + auto const stored_task_register = kernel::cpu::store_task_register(); arch::exception_handling::assert(tss_selector == stored_task_register, "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); return gdt; 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 3e93823..2385c58 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 @@ -15,7 +15,7 @@ namespace teachos::arch::context_switching::descriptor_table 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 << 40U) >> 40U) + , _base_1(base) , _access(access_byte) , _flag(flags) , _base_2(base >> 24U) diff --git a/arch/x86_64/src/kernel/cpu/tr.cpp b/arch/x86_64/src/kernel/cpu/tr.cpp index d0e037f..e281189 100644 --- a/arch/x86_64/src/kernel/cpu/tr.cpp +++ b/arch/x86_64/src/kernel/cpu/tr.cpp @@ -11,6 +11,12 @@ namespace teachos::arch::kernel::cpu auto load_task_register(uint16_t gdt_offset) -> void { - asm volatile("ltr %[input]" : /* no output from call */ : [input] "r"(gdt_offset)); + // asm volatile("ltr %[input]" : /* no output from call */ : [input] "R"(gdt_offset)); + // https://www.scs.stanford.edu/05au-cs240c/lab/i386/s07_03.htm + asm volatile("mov %[input], %%ax\n" + "ltr %%ax\n" + : /* no output from call */ + : [input] "r"(gdt_offset) + : "ax"); } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From fd557fb19c4ad25fbcb1368a73fddd91921496fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 18 Mar 2025 10:48:24 +0000 Subject: Fix invalid bit values in access byte and typo in create_segment_descriptor method --- .../src/context_switching/descriptor_table/global_descriptor_table.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src') 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 index b338d9d..578e264 100644 --- 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 @@ -19,7 +19,7 @@ namespace teachos::arch::context_switching::descriptor_table } else if (access_level == access_level::USER) { - access_level_bitset = access_byte::ACCESS_LEVEL_USER; + access_level_bitset |= access_byte::ACCESS_LEVEL_USER; } uint8_t gdt_flags_bitset = gdt_flags::GRANULARITY; -- cgit v1.2.3 From 7a98b1dcb1f4436664a8f1a5d6e71ab2c65378f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 18 Mar 2025 14:39:53 +0000 Subject: Attempt to add calls that Reload code segment and data segment register --- .../descriptor_table/global_descriptor_table.cpp | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'arch/x86_64/src') 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 index 578e264..dccce6b 100644 --- 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 @@ -94,4 +94,35 @@ namespace teachos::arch::context_switching::descriptor_table "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); return gdt; } + + auto reload_cs_register(uint16_t gdt_data_offset) -> void + { + asm volatile("mov %[input], %%ax\n" + "mov %%ax %%ds\n" // Data Segment + "mov %%ax %%es\n" // Extra Segment (used for string operations) + "mov %%ax %%fs\n" // General-purpose Segment + "mov %%ax %%gs\n" // General-purpose Segment + "mov %%ax %%ss\n" // Stack Segment + : /* no output from call */ + : [input] "r"(gdt_data_offset) + : "ax"); + } + + auto reload_segment_register(uint16_t gdt_code_offset, uint16_t gdt_data_offset) -> void + { + /* + Whatever you do with the GDT has no effect on the CPU until you load new Segment Selectors into Segment Registers. + For most of these registers, the process is as simple as using MOV instructions, but changing the CS register + requires code resembling a jump or call to elsewhere, as this is the only way its value is meant to be changed. + */ + auto function = [gdt_data_offset] { reload_cs_register(gdt_data_offset); }; + + asm volatile("push %[input]\n" + "lea %[func], %%rax\n" + "push %%rax\n" + "retfq\n" + : /* no output from call */ + : [input] "r"(gdt_code_offset), [func] "r"(&function) + : "rax"); + } } // namespace teachos::arch::context_switching::descriptor_table -- cgit v1.2.3 From b6ee8bec7ed23fd0c544f67f735e96b2bfe67682 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 20 Mar 2025 15:30:18 +0000 Subject: begin implementation of IDT --- arch/x86_64/src/boot/boot.s | 13 +++++++ .../descriptor_table/gate_descriptor.cpp | 5 +++ .../descriptor_table/global_descriptor_table.cpp | 42 ++-------------------- .../descriptor_table/initialization.cpp | 38 ++++++++++++++++++++ .../interrupt_descriptor_table.cpp | 10 ++++++ .../interrupt_descriptor_table_pointer.cpp | 13 +++++++ arch/x86_64/src/kernel/cpu/idtr.cpp | 19 ++++++++++ arch/x86_64/src/kernel/cpu/if.cpp | 5 +++ arch/x86_64/src/kernel/cpu/jmp.cpp | 16 +++++++++ arch/x86_64/src/kernel/main.cpp | 10 +++--- 10 files changed, 128 insertions(+), 43 deletions(-) create mode 100644 arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp create mode 100644 arch/x86_64/src/context_switching/descriptor_table/initialization.cpp create mode 100644 arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp create mode 100644 arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp create mode 100644 arch/x86_64/src/kernel/cpu/idtr.cpp create mode 100644 arch/x86_64/src/kernel/cpu/if.cpp create mode 100644 arch/x86_64/src/kernel/cpu/jmp.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 39bfe33..4fb23e5 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -354,7 +354,20 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 +.global segment_register_reload_pointer +segment_register_reload_pointer: + xor %rax, %rax + mov %rax, %ss + mov %rax, %ds + mov %rax, %es + mov %rax, %fs + mov %rax, %gs + + ret + _transition_to_long_mode: + call segment_register_reload_pointer + xor %rax, %rax mov %rax, %ss mov %rax, %ds diff --git a/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp new file mode 100644 index 0000000..ee91e53 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp @@ -0,0 +1,5 @@ +#include "arch/context_switching/descriptor_table/gate_descriptor.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ +} // namespace teachos::arch::context_switching::descriptor_table 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 index dccce6b..639b079 100644 --- 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 @@ -38,8 +38,8 @@ namespace teachos::arch::context_switching::descriptor_table std::bitset<20U> const limit{0xFFFFF}; access_byte const access_byte{access_level_bitset}; gdt_flags const gdt_flags{gdt_flags_bitset, limit}; - segment_descriptor const code_segment{access_byte, gdt_flags, base, limit}; - return code_segment; + segment_descriptor const segment_descriptor{access_byte, gdt_flags, base, limit}; + return segment_descriptor; } auto create_global_descriptor_table() -> global_descriptor_table @@ -53,6 +53,7 @@ namespace teachos::arch::context_switching::descriptor_table create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::USER); segment_descriptor const user_data_segment = create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); + // Task State Segment needs to be kept alive static auto tss = new task_state_segment(); segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); @@ -85,44 +86,7 @@ namespace teachos::arch::context_switching::descriptor_table gdt_pointer == stored_gdt_pointer, "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); - // Calculate the offset of the gdt in bytes to the TSS descriptor - uint16_t const tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor); - kernel::cpu::load_task_register(tss_selector); - - auto const stored_task_register = kernel::cpu::store_task_register(); - arch::exception_handling::assert(tss_selector == stored_task_register, - "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); return gdt; } - auto reload_cs_register(uint16_t gdt_data_offset) -> void - { - asm volatile("mov %[input], %%ax\n" - "mov %%ax %%ds\n" // Data Segment - "mov %%ax %%es\n" // Extra Segment (used for string operations) - "mov %%ax %%fs\n" // General-purpose Segment - "mov %%ax %%gs\n" // General-purpose Segment - "mov %%ax %%ss\n" // Stack Segment - : /* no output from call */ - : [input] "r"(gdt_data_offset) - : "ax"); - } - - auto reload_segment_register(uint16_t gdt_code_offset, uint16_t gdt_data_offset) -> void - { - /* - Whatever you do with the GDT has no effect on the CPU until you load new Segment Selectors into Segment Registers. - For most of these registers, the process is as simple as using MOV instructions, but changing the CS register - requires code resembling a jump or call to elsewhere, as this is the only way its value is meant to be changed. - */ - auto function = [gdt_data_offset] { reload_cs_register(gdt_data_offset); }; - - asm volatile("push %[input]\n" - "lea %[func], %%rax\n" - "push %%rax\n" - "retfq\n" - : /* no output from call */ - : [input] "r"(gdt_code_offset), [func] "r"(&function) - : "rax"); - } } // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp b/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp new file mode 100644 index 0000000..4d8b3e3 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp @@ -0,0 +1,38 @@ +#include "arch/context_switching/descriptor_table/initialization.hpp" + +#include "arch/boot/pointers.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/if.hpp" +#include "arch/kernel/cpu/jmp.hpp" +#include "arch/kernel/cpu/tr.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + auto initialize_descriptor_tables() -> descriptor_tables + { + decltype(auto) global_descriptor_table = context_switching::descriptor_table::initialize_global_descriptor_table(); + + // TODO: Replace random construction with return value of initialization. + interrupt_descriptor_table idt{}; + context_switching::descriptor_table::initialize_interrupt_descriptor_table(); + + kernel::cpu::jmp((uint64_t)&global_descriptor_table.at(1), boot::segment_register_reload_pointer); + + uint16_t const tss_selector = (global_descriptor_table.size() - 1) << 3; + kernel::cpu::load_task_register(tss_selector); + + // Not sure if offset index or offset in bytes is needed! + // uint16_t const tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor); + // kernel::cpu::load_task_register(tss_selector); + + auto const stored_task_register = kernel::cpu::store_task_register(); + arch::exception_handling::assert(tss_selector == stored_task_register, + "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); + + kernel::cpu::set_interrupt_flag(); + + descriptor_tables descriptor_tables = {global_descriptor_table, idt}; + return descriptor_tables; + } + +} // namespace teachos::arch::context_switching::descriptor_table \ No newline at end of file diff --git a/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp new file mode 100644 index 0000000..9878664 --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp @@ -0,0 +1,10 @@ +#include "arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + auto initialize_interrupt_descriptor_table() -> void + { + // DO NOT + } + +} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp new file mode 100644 index 0000000..b45324d --- /dev/null +++ b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp @@ -0,0 +1,13 @@ +#include "arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp" + +namespace teachos::arch::context_switching::descriptor_table +{ + interrupt_descriptor_table_pointer::interrupt_descriptor_table_pointer(uint16_t table_length, + interrupt_descriptor_table * address) + : table_length(table_length) + , address(address) + { + // Nothing to do. + } + +} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/idtr.cpp b/arch/x86_64/src/kernel/cpu/idtr.cpp new file mode 100644 index 0000000..bbf34cb --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/idtr.cpp @@ -0,0 +1,19 @@ +#include "arch/kernel/cpu/idtr.hpp" + +#include "arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto store_global_descriptor_table() -> context_switching::descriptor_table::global_descriptor_table_pointer + { + context_switching::descriptor_table::interrupt_descriptor_table_pointer current_value{}; + asm("sidt %[output]" : [output] "=m"(current_value)); + return current_value; + } + + auto load_interrupt_descriptor_table( + context_switching::descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void + { + asm volatile("lidt %[input]" : /* no output from call */ : [input] "m"(idt_pointer)); + } +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/if.cpp b/arch/x86_64/src/kernel/cpu/if.cpp new file mode 100644 index 0000000..2a25df5 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/if.cpp @@ -0,0 +1,5 @@ +namespace teachos::arch::kernel::cpu +{ + auto set_interrupt_flag() -> void { asm volatile("sti"); } + +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp new file mode 100644 index 0000000..009981b --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/jmp.cpp @@ -0,0 +1,16 @@ +#include "arch/kernel/cpu/jmp.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto jmp(uint64_t address) -> void + { + asm volatile("jmp *%[input]" : /* no output from call */ : [input] "r"(address)); + } + + auto jmp(uint64_t segment, uint64_t offset) -> void + { + far_pointer far_pointer = {offset, static_cast(segment)}; + asm volatile("jmp *%0" : : "m"(far_pointer)); + } + +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index da6d6d3..9433558 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,6 +1,9 @@ #include "arch/kernel/main.hpp" -#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" +#include "arch/boot/pointers.hpp" +#include "arch/context_switching/descriptor_table/initialization.hpp" +#include "arch/kernel/cpu/if.hpp" +#include "arch/kernel/cpu/jmp.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/main.hpp" @@ -60,8 +63,7 @@ namespace teachos::arch::kernel heap_test(); - decltype(auto) global_descriptor_table = context_switching::descriptor_table::initialize_global_descriptor_table(); - (void)global_descriptor_table.at(1); - video::vga::text::write("GDT FILLED", video::vga::text::common_attributes::green_on_black); + decltype(auto) descriptor_tables = context_switching::descriptor_table::initialize_descriptor_tables(); + (void)descriptor_tables; } } // namespace teachos::arch::kernel -- cgit v1.2.3 From ccb47845d99e098c183f596cd1a3eb1db5c676da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 25 Mar 2025 12:04:43 +0000 Subject: Adjust file structure and fix compilation issues --- .../descriptor_table/access_byte.cpp | 15 ---- .../descriptor_table/gate_descriptor.cpp | 5 -- .../descriptor_table/gdt_flags.cpp | 18 ----- .../descriptor_table/global_descriptor_table.cpp | 92 ---------------------- .../global_descriptor_table_pointer.cpp | 12 --- .../descriptor_table/initialization.cpp | 38 --------- .../interrupt_descriptor_table.cpp | 10 --- .../interrupt_descriptor_table_pointer.cpp | 13 --- .../descriptor_table/segment_descriptor.cpp | 35 -------- .../interrupt_descriptor_table/gate_descriptor.cpp | 5 ++ .../interrupt_descriptor_table.cpp | 10 +++ .../interrupt_descriptor_table_pointer.cpp | 13 +++ arch/x86_64/src/context_switching/main.cpp | 36 +++++++++ .../segment_descriptor_table/access_byte.cpp | 15 ++++ .../segment_descriptor_table/gdt_flags.cpp | 18 +++++ .../global_descriptor_table.cpp | 92 ++++++++++++++++++++++ .../global_descriptor_table_pointer.cpp | 12 +++ .../segment_descriptor.cpp | 35 ++++++++ arch/x86_64/src/kernel/cpu/gdtr.cpp | 11 ++- arch/x86_64/src/kernel/cpu/idtr.cpp | 9 +-- arch/x86_64/src/kernel/main.cpp | 4 +- 21 files changed, 247 insertions(+), 251 deletions(-) delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/initialization.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp delete mode 100644 arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp create mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp create mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp create mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp create mode 100644 arch/x86_64/src/context_switching/main.cpp create mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp create mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp create mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp create mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp create mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp (limited to 'arch/x86_64/src') 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 deleted file mode 100644 index 6b54451..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/access_byte.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "arch/context_switching/descriptor_table/access_byte.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - access_byte::access_byte(uint8_t flags) - : _flags(flags) - { - // Nothing to do. - } - - auto access_byte::contains_flags(std::bitset<8U> other) const -> bool - { - return (std::bitset<8U>{_flags} & other) == other; - } -} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp deleted file mode 100644 index ee91e53..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/gate_descriptor.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "arch/context_switching/descriptor_table/gate_descriptor.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ -} // 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 deleted file mode 100644 index 9e95182..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/gdt_flags.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "arch/context_switching/descriptor_table/gdt_flags.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - gdt_flags::gdt_flags(uint8_t flags, std::bitset<20U> limit) - : _limit_2(limit.to_ulong() >> 16U) - , _flags(flags) - { - // Nothing to do. - } - - auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool - { - return (std::bitset<4U>{_flags} & other) == other; - } - - auto descriptor_table::gdt_flags::get_limit() const -> std::bitset<4U> { return std::bitset<4U>{_limit_2}; } -} // namespace teachos::arch::context_switching::descriptor_table 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 deleted file mode 100644 index 639b079..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "arch/context_switching/descriptor_table/global_descriptor_table.hpp" - -#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" -#include "arch/context_switching/descriptor_table/task_state_segment.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/kernel/cpu/gdtr.hpp" -#include "arch/kernel/cpu/tr.hpp" -#include "arch/stl/vector.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_level access_level) - -> segment_descriptor - { - uint8_t access_level_bitset = access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT; - if (access_level == access_level::KERNEL) - { - access_level_bitset |= access_byte::ACCESS_LEVEL_KERNEL; - } - else if (access_level == access_level::USER) - { - access_level_bitset |= access_byte::ACCESS_LEVEL_USER; - } - - uint8_t gdt_flags_bitset = gdt_flags::GRANULARITY; - if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) - { - gdt_flags_bitset |= gdt_flags::LENGTH; - access_level_bitset |= access_byte::CODE_SEGMENT | access_byte::READABLE; - } - else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) - { - gdt_flags_bitset |= gdt_flags::UPPER_BOUND; - access_level_bitset |= access_byte::WRITABLE; - } - - uint64_t const base = 0x0; - std::bitset<20U> const limit{0xFFFFF}; - access_byte const access_byte{access_level_bitset}; - gdt_flags const gdt_flags{gdt_flags_bitset, limit}; - segment_descriptor const segment_descriptor{access_byte, gdt_flags, base, limit}; - return segment_descriptor; - } - - auto create_global_descriptor_table() -> global_descriptor_table - { - segment_descriptor const null_segment{0}; - segment_descriptor const kernel_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::KERNEL); - segment_descriptor const kernel_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::KERNEL); - segment_descriptor const user_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::USER); - segment_descriptor const user_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); - - // Task State Segment needs to be kept alive - static auto tss = new task_state_segment(); - segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); - - global_descriptor_table const global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment, tss_descriptor}; - return global_descriptor_table; - } - - auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor - { - constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; - access_byte const tss_access_byte{access_byte::PRESENT | access_byte::ACCESS_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(tss), TSS_LIMIT}; - return tss_descriptor; - } - - auto initialize_global_descriptor_table() -> global_descriptor_table & - { - // Global Descriptor Table needs to be kept alive - static auto gdt = create_global_descriptor_table(); - - global_descriptor_table_pointer gdt_pointer{static_cast(gdt.size() - 1), &gdt}; - kernel::cpu::load_global_descriptor_table(gdt_pointer); - - auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); - arch::exception_handling::assert( - gdt_pointer == stored_gdt_pointer, - "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); - - return gdt; - } - -} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp deleted file mode 100644 index f552496..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/global_descriptor_table_pointer.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, - global_descriptor_table * address) - : table_length(table_length) - , address(address) - { - // Nothing to do. - } -} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp b/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp deleted file mode 100644 index 4d8b3e3..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/initialization.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "arch/context_switching/descriptor_table/initialization.hpp" - -#include "arch/boot/pointers.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/jmp.hpp" -#include "arch/kernel/cpu/tr.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - auto initialize_descriptor_tables() -> descriptor_tables - { - decltype(auto) global_descriptor_table = context_switching::descriptor_table::initialize_global_descriptor_table(); - - // TODO: Replace random construction with return value of initialization. - interrupt_descriptor_table idt{}; - context_switching::descriptor_table::initialize_interrupt_descriptor_table(); - - kernel::cpu::jmp((uint64_t)&global_descriptor_table.at(1), boot::segment_register_reload_pointer); - - uint16_t const tss_selector = (global_descriptor_table.size() - 1) << 3; - kernel::cpu::load_task_register(tss_selector); - - // Not sure if offset index or offset in bytes is needed! - // uint16_t const tss_selector = (gdt.size() - 1) * sizeof(segment_descriptor); - // kernel::cpu::load_task_register(tss_selector); - - auto const stored_task_register = kernel::cpu::store_task_register(); - arch::exception_handling::assert(tss_selector == stored_task_register, - "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); - - kernel::cpu::set_interrupt_flag(); - - descriptor_tables descriptor_tables = {global_descriptor_table, idt}; - return descriptor_tables; - } - -} // namespace teachos::arch::context_switching::descriptor_table \ No newline at end of file diff --git a/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp deleted file mode 100644 index 9878664..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "arch/context_switching/descriptor_table/interrupt_descriptor_table.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - auto initialize_interrupt_descriptor_table() -> void - { - // DO NOT - } - -} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp deleted file mode 100644 index b45324d..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/interrupt_descriptor_table_pointer.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - interrupt_descriptor_table_pointer::interrupt_descriptor_table_pointer(uint16_t table_length, - interrupt_descriptor_table * address) - : table_length(table_length) - , address(address) - { - // Nothing to do. - } - -} // namespace teachos::arch::context_switching::descriptor_table 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 deleted file mode 100644 index 2385c58..0000000 --- a/arch/x86_64/src/context_switching/descriptor_table/segment_descriptor.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "arch/context_switching/descriptor_table/segment_descriptor.hpp" - -namespace teachos::arch::context_switching::descriptor_table -{ - segment_descriptor::segment_descriptor(uint128_t flags) - : _limit_1(flags << 112U) - , _base_1((flags >> 16U) << 88U) - , _access((flags >> 40U) << 80U) - , _flag((flags >> 52U) << 72U, (flags >> 48U) << 72U) - , _base_2((flags >> 56U) << 32U) - { - // 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 - } - - 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.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT - : segment_descriptor_type::DATA_SEGMENT; - } -} // namespace teachos::arch::context_switching::descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp new file mode 100644 index 0000000..4f18197 --- /dev/null +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp @@ -0,0 +1,5 @@ +#include "arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ +} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp new file mode 100644 index 0000000..619a695 --- /dev/null +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -0,0 +1,10 @@ +#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + auto initialize_interrupt_descriptor_table() -> void + { + // DO NOT + } + +} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp new file mode 100644 index 0000000..981944d --- /dev/null +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp @@ -0,0 +1,13 @@ +#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + interrupt_descriptor_table_pointer::interrupt_descriptor_table_pointer(uint16_t table_length, + interrupt_descriptor_table * address) + : table_length(table_length) + , address(address) + { + // Nothing to do. + } + +} // 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 new file mode 100644 index 0000000..b682e79 --- /dev/null +++ b/arch/x86_64/src/context_switching/main.cpp @@ -0,0 +1,36 @@ +#include "arch/context_switching/main.hpp" + +#include "arch/boot/pointers.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/if.hpp" +#include "arch/kernel/cpu/jmp.hpp" +#include "arch/kernel/cpu/tr.hpp" + +namespace teachos::arch::context_switching +{ + auto initialize_descriptor_tables() -> descriptor_tables + { + decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); + + // TODO: Replace random construction with return value of initialization. + interrupt_descriptor_table::interrupt_descriptor_table idt{}; + interrupt_descriptor_table::initialize_interrupt_descriptor_table(); + + kernel::cpu::jmp((uint64_t)&global_descriptor_table.at(1), boot::segment_register_reload_pointer); + + // 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 = + (global_descriptor_table.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); + kernel::cpu::load_task_register(tss_selector); + + auto const stored_task_register = kernel::cpu::store_task_register(); + arch::exception_handling::assert(tss_selector == stored_task_register, + "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); + + kernel::cpu::set_interrupt_flag(); + + descriptor_tables tables = {global_descriptor_table, idt}; + return tables; + } +} // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp new file mode 100644 index 0000000..34a10f1 --- /dev/null +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp @@ -0,0 +1,15 @@ +#include "arch/context_switching/segment_descriptor_table/access_byte.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + access_byte::access_byte(uint8_t flags) + : _flags(flags) + { + // Nothing to do. + } + + auto access_byte::contains_flags(std::bitset<8U> other) const -> bool + { + return (std::bitset<8U>{_flags} & other) == other; + } +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp new file mode 100644 index 0000000..9885bda --- /dev/null +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp @@ -0,0 +1,18 @@ +#include "arch/context_switching/segment_descriptor_table/gdt_flags.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + gdt_flags::gdt_flags(uint8_t flags, std::bitset<20U> limit) + : _limit_2(limit.to_ulong() >> 16U) + , _flags(flags) + { + // Nothing to do. + } + + auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool + { + return (std::bitset<4U>{_flags} & other) == other; + } + + auto gdt_flags::get_limit() const -> std::bitset<4U> { return std::bitset<4U>{_limit_2}; } +} // namespace teachos::arch::context_switching::segment_descriptor_table 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 new file mode 100644 index 0000000..1bbd24f --- /dev/null +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp @@ -0,0 +1,92 @@ +#include "arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp" + +#include "arch/context_switching/segment_descriptor_table/segment_descriptor.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" +#include "arch/stl/vector.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_level access_level) + -> segment_descriptor + { + uint8_t access_level_bitset = access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT; + if (access_level == access_level::KERNEL) + { + access_level_bitset |= access_byte::ACCESS_LEVEL_KERNEL; + } + else if (access_level == access_level::USER) + { + access_level_bitset |= access_byte::ACCESS_LEVEL_USER; + } + + uint8_t gdt_flags_bitset = gdt_flags::GRANULARITY; + if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) + { + gdt_flags_bitset |= gdt_flags::LENGTH; + access_level_bitset |= access_byte::CODE_SEGMENT | access_byte::READABLE; + } + else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) + { + gdt_flags_bitset |= gdt_flags::UPPER_BOUND; + access_level_bitset |= access_byte::WRITABLE; + } + + uint64_t const base = 0x0; + std::bitset<20U> const limit{0xFFFFF}; + access_byte const access_byte{access_level_bitset}; + gdt_flags const gdt_flags{gdt_flags_bitset, limit}; + segment_descriptor const segment_descriptor{access_byte, gdt_flags, base, limit}; + return segment_descriptor; + } + + auto create_global_descriptor_table() -> global_descriptor_table + { + segment_descriptor const null_segment{0}; + segment_descriptor const kernel_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::KERNEL); + segment_descriptor const kernel_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::KERNEL); + segment_descriptor const user_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::USER); + segment_descriptor const user_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); + + // Task State Segment needs to be kept alive + static auto tss = new task_state_segment(); + segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); + + global_descriptor_table const global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment, tss_descriptor}; + return global_descriptor_table; + } + + auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor + { + constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; + access_byte const tss_access_byte{access_byte::PRESENT | access_byte::ACCESS_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(tss), TSS_LIMIT}; + return tss_descriptor; + } + + auto initialize_global_descriptor_table() -> global_descriptor_table & + { + // Global Descriptor Table needs to be kept alive + static auto gdt = create_global_descriptor_table(); + + global_descriptor_table_pointer gdt_pointer{static_cast(gdt.size() - 1), &gdt}; + kernel::cpu::load_global_descriptor_table(gdt_pointer); + + auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); + arch::exception_handling::assert( + gdt_pointer == stored_gdt_pointer, + "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); + + return gdt; + } + +} // namespace teachos::arch::context_switching::segment_descriptor_table 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 new file mode 100644 index 0000000..132565f --- /dev/null +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp @@ -0,0 +1,12 @@ +#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, + global_descriptor_table * address) + : table_length(table_length) + , address(address) + { + // Nothing to do. + } +} // namespace teachos::arch::context_switching::segment_descriptor_table 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 new file mode 100644 index 0000000..6d831a1 --- /dev/null +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp @@ -0,0 +1,35 @@ +#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 << 112U) + , _base_1((flags >> 16U) << 88U) + , _access((flags >> 40U) << 80U) + , _flag((flags >> 52U) << 72U, (flags >> 48U) << 72U) + , _base_2((flags >> 56U) << 32U) + { + // 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 + } + + 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.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT + : segment_descriptor_type::DATA_SEGMENT; + } +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/gdtr.cpp b/arch/x86_64/src/kernel/cpu/gdtr.cpp index 2fe3a99..74a4e1c 100644 --- a/arch/x86_64/src/kernel/cpu/gdtr.cpp +++ b/arch/x86_64/src/kernel/cpu/gdtr.cpp @@ -1,19 +1,18 @@ #include "arch/kernel/cpu/gdtr.hpp" -#include "arch/context_switching/descriptor_table/global_descriptor_table_pointer.hpp" +#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" namespace teachos::arch::kernel::cpu { - auto store_global_descriptor_table() -> context_switching::descriptor_table::global_descriptor_table_pointer + auto store_global_descriptor_table() -> context_switching::segment_descriptor_table::global_descriptor_table_pointer { - context_switching::descriptor_table::global_descriptor_table_pointer current_value{}; + context_switching::segment_descriptor_table::global_descriptor_table_pointer current_value{}; asm("sgdt %[output]" : [output] "=m"(current_value)); return current_value; } - auto - load_global_descriptor_table(context_switching::descriptor_table::global_descriptor_table_pointer const & gdt_pointer) - -> void + auto load_global_descriptor_table( + context_switching::segment_descriptor_table::global_descriptor_table_pointer const & gdt_pointer) -> void { asm volatile("lgdt %[input]" : /* no output from call */ : [input] "m"(gdt_pointer)); } diff --git a/arch/x86_64/src/kernel/cpu/idtr.cpp b/arch/x86_64/src/kernel/cpu/idtr.cpp index bbf34cb..7aa20c1 100644 --- a/arch/x86_64/src/kernel/cpu/idtr.cpp +++ b/arch/x86_64/src/kernel/cpu/idtr.cpp @@ -1,18 +1,17 @@ #include "arch/kernel/cpu/idtr.hpp" -#include "arch/context_switching/descriptor_table/interrupt_descriptor_table_pointer.hpp" - namespace teachos::arch::kernel::cpu { - auto store_global_descriptor_table() -> context_switching::descriptor_table::global_descriptor_table_pointer + auto store_interrupt_descriptor_table() + -> context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer { - context_switching::descriptor_table::interrupt_descriptor_table_pointer current_value{}; + context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer current_value{}; asm("sidt %[output]" : [output] "=m"(current_value)); return current_value; } auto load_interrupt_descriptor_table( - context_switching::descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void + context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void { asm volatile("lidt %[input]" : /* no output from call */ : [input] "m"(idt_pointer)); } diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 9433558..7782d30 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,7 +1,7 @@ #include "arch/kernel/main.hpp" #include "arch/boot/pointers.hpp" -#include "arch/context_switching/descriptor_table/initialization.hpp" +#include "arch/context_switching/main.hpp" #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/jmp.hpp" #include "arch/memory/heap/bump_allocator.hpp" @@ -63,7 +63,7 @@ namespace teachos::arch::kernel heap_test(); - decltype(auto) descriptor_tables = context_switching::descriptor_table::initialize_descriptor_tables(); + decltype(auto) descriptor_tables = context_switching::initialize_descriptor_tables(); (void)descriptor_tables; } } // namespace teachos::arch::kernel -- cgit v1.2.3 From 66fefaeb16bcbc4eae5ce5256ae76f51a155cded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 25 Mar 2025 16:58:24 +0000 Subject: Implement idtr structure and document possible flags. --- .../interrupt_descriptor_table/gate_descriptor.cpp | 19 ++++ .../interrupt_descriptor_table/idt_flags.cpp | 15 +++ .../interrupt_descriptor_table.cpp | 24 ++++- .../interrupt_descriptor_table/ist_offset.cpp | 10 ++ .../segment_selector.cpp | 16 ++++ arch/x86_64/src/context_switching/main.cpp | 7 +- .../global_descriptor_table.cpp | 105 ++++++++++----------- .../segment_descriptor.cpp | 10 +- arch/x86_64/src/kernel/cpu/ss.cpp | 29 ++---- 9 files changed, 145 insertions(+), 90 deletions(-) create mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp create mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp create mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp index 4f18197..28f289c 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp @@ -2,4 +2,23 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { + gate_descriptor::gate_descriptor(uint128_t flags) + : _offset_1(flags) + , _selector(flags >> 19U, flags >> 16U) + , _ist(flags >> 32U) + , _flags(flags >> 40U) + , _offset_2(flags >> 48U) + { + // Nothing to do. + } + + gate_descriptor::gate_descriptor(segment_selector selector, ist_offset ist, idt_flags flags, uint64_t offset) + : _offset_1(offset) + , _selector(selector) + , _ist(ist) + , _flags(flags) + , _offset_2(offset >> 16U) + { + // Nothing to do. + } } // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp new file mode 100644 index 0000000..e7379ef --- /dev/null +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp @@ -0,0 +1,15 @@ +#include "arch/context_switching/interrupt_descriptor_table/idt_flags.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + idt_flags::idt_flags(uint8_t flags) + : _flags(flags) + { + // Nothing to do. + } + + auto idt_flags::contains_flags(std::bitset<8U> other) const -> bool + { + return (std::bitset<8U>{_flags} & other) == other; + } +} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 619a695..7346248 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -1,10 +1,28 @@ #include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/idtr.hpp" + namespace teachos::arch::context_switching::interrupt_descriptor_table { - auto initialize_interrupt_descriptor_table() -> void + namespace { - // DO NOT - } + auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { return interrupt_descriptor_table{}; } + } // namespace + + auto initialize_interrupt_descriptor_table() -> interrupt_descriptor_table & + { + // Interrupt Descriptor Table needs to be kept alive + static auto idt = create_interrupt_descriptor_table(); + interrupt_descriptor_table_pointer idt_pointer{static_cast(idt.size() - 1), &idt}; + kernel::cpu::load_interrupt_descriptor_table(idt_pointer); + + auto const stored_gdt_pointer = kernel::cpu::store_interrupt_descriptor_table(); + arch::exception_handling::assert( + idt_pointer == stored_gdt_pointer, + "[Interrupt Descriptor Table] Loaded IDTR value is not the same as the stored value."); + + return idt; + } } // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp new file mode 100644 index 0000000..a70e75d --- /dev/null +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp @@ -0,0 +1,10 @@ +#include "arch/context_switching/interrupt_descriptor_table/ist_offset.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + ist_offset::ist_offset(uint8_t index) + : _ist(index) + { + // Nothing to do. + } +} // namespace teachos::arch::context_switching::interrupt_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 new file mode 100644 index 0000000..494e50f --- /dev/null +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp @@ -0,0 +1,16 @@ +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" + +namespace teachos::arch::context_switching::interrupt_descriptor_table +{ + segment_selector::segment_selector(uint16_t index, uint8_t flags) + : _flags(flags) + , _index(index) + { + // Nothing to do. + } + + auto segment_selector::contains_flags(std::bitset<3U> other) const -> bool + { + return (std::bitset<3U>{_flags} & other) == other; + } +} // 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 b682e79..95a25e0 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -11,10 +11,7 @@ namespace teachos::arch::context_switching auto initialize_descriptor_tables() -> descriptor_tables { decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); - - // TODO: Replace random construction with return value of initialization. - interrupt_descriptor_table::interrupt_descriptor_table idt{}; - interrupt_descriptor_table::initialize_interrupt_descriptor_table(); + decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table(); kernel::cpu::jmp((uint64_t)&global_descriptor_table.at(1), boot::segment_register_reload_pointer); @@ -30,7 +27,7 @@ namespace teachos::arch::context_switching kernel::cpu::set_interrupt_flag(); - descriptor_tables tables = {global_descriptor_table, idt}; + descriptor_tables tables = {global_descriptor_table, interrupt_descriptor_table}; return tables; } } // namespace teachos::arch::context_switching 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 1bbd24f..69cce19 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 @@ -9,69 +9,66 @@ namespace teachos::arch::context_switching::segment_descriptor_table { - auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_level access_level) - -> segment_descriptor + namespace { - uint8_t access_level_bitset = access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT; - if (access_level == access_level::KERNEL) - { - access_level_bitset |= access_byte::ACCESS_LEVEL_KERNEL; - } - else if (access_level == access_level::USER) - { - access_level_bitset |= access_byte::ACCESS_LEVEL_USER; - } - uint8_t gdt_flags_bitset = gdt_flags::GRANULARITY; - if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) + auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_byte access_level) + -> segment_descriptor { - gdt_flags_bitset |= gdt_flags::LENGTH; - access_level_bitset |= access_byte::CODE_SEGMENT | access_byte::READABLE; + uint8_t access_level_bits = + access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT | *reinterpret_cast(&access_level); + uint8_t gdt_flags_bits = gdt_flags::GRANULARITY; + if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) + { + gdt_flags_bits |= gdt_flags::LENGTH; + access_level_bits |= access_byte::CODE_SEGMENT | access_byte::READABLE; + } + else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) + { + gdt_flags_bits |= gdt_flags::UPPER_BOUND; + access_level_bits |= access_byte::WRITABLE; + } + + uint64_t const base = 0x0; + std::bitset<20U> const limit{0xFFFFF}; + access_byte const access_byte{access_level_bits}; + gdt_flags const gdt_flags{gdt_flags_bits, limit}; + segment_descriptor const segment_descriptor{access_byte, gdt_flags, base, limit}; + return segment_descriptor; } - else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) + + auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor { - gdt_flags_bitset |= gdt_flags::UPPER_BOUND; - access_level_bitset |= access_byte::WRITABLE; + 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(tss), + TSS_LIMIT}; + return tss_descriptor; } - uint64_t const base = 0x0; - std::bitset<20U> const limit{0xFFFFF}; - access_byte const access_byte{access_level_bitset}; - gdt_flags const gdt_flags{gdt_flags_bitset, limit}; - segment_descriptor const segment_descriptor{access_byte, gdt_flags, base, limit}; - return segment_descriptor; - } - - auto create_global_descriptor_table() -> global_descriptor_table - { - segment_descriptor const null_segment{0}; - segment_descriptor const kernel_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::KERNEL); - segment_descriptor const kernel_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::KERNEL); - segment_descriptor const user_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_level::USER); - segment_descriptor const user_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_level::USER); - - // Task State Segment needs to be kept alive - static auto tss = new task_state_segment(); - segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); + auto create_global_descriptor_table() -> global_descriptor_table + { + segment_descriptor const null_segment{0}; + segment_descriptor const kernel_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor const kernel_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor const user_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); + segment_descriptor const user_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); - global_descriptor_table const global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment, tss_descriptor}; - return global_descriptor_table; - } + // Task State Segment needs to be kept alive + static auto tss = new task_state_segment(); + segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); - auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor - { - constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; - access_byte const tss_access_byte{access_byte::PRESENT | access_byte::ACCESS_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(tss), TSS_LIMIT}; - return tss_descriptor; - } + global_descriptor_table const global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment, tss_descriptor}; + return global_descriptor_table; + } + } // namespace auto initialize_global_descriptor_table() -> global_descriptor_table & { 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 index 6d831a1..74f93b2 100644 --- 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 @@ -3,11 +3,11 @@ namespace teachos::arch::context_switching::segment_descriptor_table { segment_descriptor::segment_descriptor(uint128_t flags) - : _limit_1(flags << 112U) - , _base_1((flags >> 16U) << 88U) - , _access((flags >> 40U) << 80U) - , _flag((flags >> 52U) << 72U, (flags >> 48U) << 72U) - , _base_2((flags >> 56U) << 32U) + : _limit_1(flags) + , _base_1(flags >> 16U) + , _access(flags >> 40U) + , _flag(flags >> 52U, flags >> 48U) + , _base_2(flags >> 56U) { // Nothing to do. } diff --git a/arch/x86_64/src/kernel/cpu/ss.cpp b/arch/x86_64/src/kernel/cpu/ss.cpp index 1f28e7f..0978eca 100644 --- a/arch/x86_64/src/kernel/cpu/ss.cpp +++ b/arch/x86_64/src/kernel/cpu/ss.cpp @@ -2,32 +2,15 @@ namespace teachos::arch::kernel::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) + auto read_ss() -> context_switching::interrupt_descriptor_table::segment_selector { - // 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 segment_selector; - asm volatile("mov %%ss, %[output]" : [output] "=r"(segment_selector)); + context_switching::interrupt_descriptor_table::segment_selector segment_selector{}; + asm volatile("mov %%ss, %[output]" : [output] "=m"(segment_selector)); return segment_selector; } - auto write_ss(segment_selector selector) -> void + auto write_ss(context_switching::interrupt_descriptor_table::segment_selector selector) -> void { - uint16_t ss = selector.to_uint16(); - asm volatile("mov %[input], %%ss" : /* no output from call */ : [input] "r"(ss)); + asm volatile("mov %[input], %%ss" : /* no output from call */ : [input] "m"(selector)); } - -} // namespace teachos::arch::kernel::cpu \ No newline at end of file +} // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 96711d45ad7fb5b96cfd2b4fffda8756fe68fcd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 26 Mar 2025 09:33:44 +0000 Subject: Fixing pointer values and adding basic idt value --- .../interrupt_descriptor_table.cpp | 20 ++++++++++++++++++-- .../global_descriptor_table.cpp | 5 ++++- 2 files changed, 22 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 7346248..8bcce65 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -7,7 +7,22 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { namespace { - auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { return interrupt_descriptor_table{}; } + auto create_interrupt_descriptor_table() -> interrupt_descriptor_table + { + // TODO: Fix offset and ist and selector index + uint64_t const offset = 0x0; + segment_selector const selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; + ist_offset const ist{0U}; + idt_flags const flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE}; + gate_descriptor const interrupt_gate{selector, ist, flags, offset}; + + segment_selector const selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; + ist_offset const ist{0U}; + idt_flags const flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::TRAP_GATE}; + gate_descriptor const trap_gate{selector, ist, flags, offset}; + + return interrupt_descriptor_table{interrupt_gate, trap_gate}; + } } // namespace auto initialize_interrupt_descriptor_table() -> interrupt_descriptor_table & @@ -15,7 +30,8 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table // Interrupt Descriptor Table needs to be kept alive static auto idt = create_interrupt_descriptor_table(); - interrupt_descriptor_table_pointer idt_pointer{static_cast(idt.size() - 1), &idt}; + interrupt_descriptor_table_pointer idt_pointer{static_cast((idt.size() * sizeof(gate_descriptor)) - 1), + &idt}; kernel::cpu::load_interrupt_descriptor_table(idt_pointer); auto const stored_gdt_pointer = kernel::cpu::store_interrupt_descriptor_table(); 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 69cce19..e6a489c 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 @@ -75,7 +75,10 @@ namespace teachos::arch::context_switching::segment_descriptor_table // Global Descriptor Table needs to be kept alive static auto gdt = create_global_descriptor_table(); - global_descriptor_table_pointer gdt_pointer{static_cast(gdt.size() - 1), &gdt}; + // 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((gdt.size() * sizeof(segment_descriptor)) - 1), + &gdt}; kernel::cpu::load_global_descriptor_table(gdt_pointer); auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); -- cgit v1.2.3 From db555089dea369d9dd3010d1853077e7a4118b90 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Wed, 26 Mar 2025 10:08:40 +0000 Subject: add llm suggestion to idt creation --- .../interrupt_descriptor_table.cpp | 29 ++++++++++++---------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 8bcce65..0555e4c 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -9,19 +9,22 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { - // TODO: Fix offset and ist and selector index - uint64_t const offset = 0x0; - segment_selector const selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; - ist_offset const ist{0U}; - idt_flags const flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE}; - gate_descriptor const interrupt_gate{selector, ist, flags, offset}; - - segment_selector const selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; - ist_offset const ist{0U}; - idt_flags const flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::TRAP_GATE}; - gate_descriptor const trap_gate{selector, ist, flags, offset}; - - return interrupt_descriptor_table{interrupt_gate, trap_gate}; + interrupt_descriptor_table idt{}; + + // Define basic exception handlers (at least for CPU exceptions 0x00-0x1F) + for (uint8_t vector = 0; vector < 32; ++vector) + { + uint64_t offset = reinterpret_cast(default_exception_handler); // Use a real handler function + segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; + ist_offset ist{0U}; // Default stack offset (can be updated for IST) + idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::TRAP_GATE}; + + idt.push_back(gate_descriptor{selector, ist, flags, offset}); + } + + // Additional entries for hardware interrupts (IRQs) and syscalls can be added here + + return idt; } } // namespace -- cgit v1.2.3 From a6c5f6a273d0c5c4161f600fca6d4fe49858c23c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 27 Mar 2025 09:40:32 +0000 Subject: Attempt to fix crash in far jump. WIP does not return from call to assembler method --- arch/x86_64/src/boot/boot.s | 2 +- .../interrupt_descriptor_table.cpp | 22 ++++++---------------- arch/x86_64/src/context_switching/main.cpp | 5 ++++- arch/x86_64/src/kernel/cpu/if.cpp | 2 ++ arch/x86_64/src/kernel/cpu/jmp.cpp | 6 ++---- 5 files changed, 15 insertions(+), 22 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 4fb23e5..35a6121 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -366,7 +366,7 @@ segment_register_reload_pointer: ret _transition_to_long_mode: - call segment_register_reload_pointer + //call segment_register_reload_pointer xor %rax, %rax mov %rax, %ss diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 0555e4c..ddc098e 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -9,22 +9,12 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { - interrupt_descriptor_table idt{}; - - // Define basic exception handlers (at least for CPU exceptions 0x00-0x1F) - for (uint8_t vector = 0; vector < 32; ++vector) - { - uint64_t offset = reinterpret_cast(default_exception_handler); // Use a real handler function - segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; - ist_offset ist{0U}; // Default stack offset (can be updated for IST) - idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::TRAP_GATE}; - - idt.push_back(gate_descriptor{selector, ist, flags, offset}); - } - - // Additional entries for hardware interrupts (IRQs) and syscalls can be added here - - return idt; + uint64_t offset = 0U; + segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; + ist_offset ist{0U}; + idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL}; + gate_descriptor gate_descriptor{selector, ist, flags, offset}; + return interrupt_descriptor_table{gate_descriptor}; } } // namespace diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 95a25e0..c3c0cf0 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -13,7 +13,10 @@ namespace teachos::arch::context_switching decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table(); - kernel::cpu::jmp((uint64_t)&global_descriptor_table.at(1), boot::segment_register_reload_pointer); + interrupt_descriptor_table::segment_selector segment_selector{ + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + kernel::cpu::far_pointer pointer{boot::segment_register_reload_pointer, segment_selector}; + kernel::cpu::jmp(pointer); // 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 diff --git a/arch/x86_64/src/kernel/cpu/if.cpp b/arch/x86_64/src/kernel/cpu/if.cpp index 2a25df5..60a90a3 100644 --- a/arch/x86_64/src/kernel/cpu/if.cpp +++ b/arch/x86_64/src/kernel/cpu/if.cpp @@ -2,4 +2,6 @@ namespace teachos::arch::kernel::cpu { auto set_interrupt_flag() -> void { asm volatile("sti"); } + auto clear_interrupt_flag() -> void { asm volatile("cli"); } + } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp index 009981b..205c4a9 100644 --- a/arch/x86_64/src/kernel/cpu/jmp.cpp +++ b/arch/x86_64/src/kernel/cpu/jmp.cpp @@ -7,10 +7,8 @@ namespace teachos::arch::kernel::cpu asm volatile("jmp *%[input]" : /* no output from call */ : [input] "r"(address)); } - auto jmp(uint64_t segment, uint64_t offset) -> void + auto jmp(far_pointer pointer) -> void { - far_pointer far_pointer = {offset, static_cast(segment)}; - asm volatile("jmp *%0" : : "m"(far_pointer)); + asm volatile("jmp *%[input]" : /* no output from call */ : [input] "m"(pointer)); } - } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 9ddfcd02413a93718e8cde53f9ba5a96a5b29b8f Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 27 Mar 2025 14:02:05 +0000 Subject: update long jump handling --- arch/x86_64/src/boot/boot.s | 16 ++++++---------- arch/x86_64/src/context_switching/main.cpp | 6 ++---- arch/x86_64/src/kernel/cpu/jmp.cpp | 10 ++++++---- 3 files changed, 14 insertions(+), 18 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 35a6121..f6c7978 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -354,8 +354,11 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 -.global segment_register_reload_pointer -segment_register_reload_pointer: +.global reload_segment_register_trampoline +reload_segment_register_trampoline: + jmp 0x08, $_reload_cs + +_reload_cs: xor %rax, %rax mov %rax, %ss mov %rax, %ds @@ -366,14 +369,7 @@ segment_register_reload_pointer: ret _transition_to_long_mode: - //call segment_register_reload_pointer - - xor %rax, %rax - mov %rax, %ss - mov %rax, %ds - mov %rax, %es - mov %rax, %fs - mov %rax, %gs + call _reload_cs movl $0xb8000, (vga_buffer_pointer) diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index c3c0cf0..1417a25 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -13,10 +13,8 @@ namespace teachos::arch::context_switching decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table(); - interrupt_descriptor_table::segment_selector segment_selector{ - 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{boot::segment_register_reload_pointer, segment_selector}; - kernel::cpu::jmp(pointer); + // Execute trampoline function for the GDT loading long jump + boot::reload_segment_register_trampoline(); // 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 diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp index 205c4a9..78b65f4 100644 --- a/arch/x86_64/src/kernel/cpu/jmp.cpp +++ b/arch/x86_64/src/kernel/cpu/jmp.cpp @@ -7,8 +7,10 @@ namespace teachos::arch::kernel::cpu asm volatile("jmp *%[input]" : /* no output from call */ : [input] "r"(address)); } - auto jmp(far_pointer pointer) -> void - { - asm volatile("jmp *%[input]" : /* no output from call */ : [input] "m"(pointer)); - } + // auto jmp(far_pointer pointer) -> void + // { + // asm volatile("ljmp $[segment_selector],$[address]" + // : /* no output from call */ + // : [segment_selector] "m"(pointer.selector), [address] "m"(pointer.offset)); + // } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From e0eae9b9e905a1842b333823bfdb7c253cda8d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 28 Mar 2025 09:59:09 +0000 Subject: Revert "update long jump handling" This reverts commit 9ddfcd02413a93718e8cde53f9ba5a96a5b29b8f. --- arch/x86_64/src/boot/boot.s | 16 ++++++++++------ arch/x86_64/src/context_switching/main.cpp | 6 ++++-- arch/x86_64/src/kernel/cpu/jmp.cpp | 10 ++++------ 3 files changed, 18 insertions(+), 14 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index f6c7978..35a6121 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -354,11 +354,8 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 -.global reload_segment_register_trampoline -reload_segment_register_trampoline: - jmp 0x08, $_reload_cs - -_reload_cs: +.global segment_register_reload_pointer +segment_register_reload_pointer: xor %rax, %rax mov %rax, %ss mov %rax, %ds @@ -369,7 +366,14 @@ _reload_cs: ret _transition_to_long_mode: - call _reload_cs + //call segment_register_reload_pointer + + xor %rax, %rax + mov %rax, %ss + mov %rax, %ds + mov %rax, %es + mov %rax, %fs + mov %rax, %gs movl $0xb8000, (vga_buffer_pointer) diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 1417a25..c3c0cf0 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -13,8 +13,10 @@ namespace teachos::arch::context_switching decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table(); - // Execute trampoline function for the GDT loading long jump - boot::reload_segment_register_trampoline(); + interrupt_descriptor_table::segment_selector segment_selector{ + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + kernel::cpu::far_pointer pointer{boot::segment_register_reload_pointer, segment_selector}; + kernel::cpu::jmp(pointer); // 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 diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp index 78b65f4..205c4a9 100644 --- a/arch/x86_64/src/kernel/cpu/jmp.cpp +++ b/arch/x86_64/src/kernel/cpu/jmp.cpp @@ -7,10 +7,8 @@ namespace teachos::arch::kernel::cpu asm volatile("jmp *%[input]" : /* no output from call */ : [input] "r"(address)); } - // auto jmp(far_pointer pointer) -> void - // { - // asm volatile("ljmp $[segment_selector],$[address]" - // : /* no output from call */ - // : [segment_selector] "m"(pointer.selector), [address] "m"(pointer.offset)); - // } + auto jmp(far_pointer pointer) -> void + { + asm volatile("jmp *%[input]" : /* no output from call */ : [input] "m"(pointer)); + } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 437c3554f9a86b6347d97f5e2a82543c1e068b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 28 Mar 2025 10:52:25 +0000 Subject: Attempt to fix ljmp. Might not be possible in Long mode --- arch/x86_64/src/boot/boot.s | 6 +++--- arch/x86_64/src/context_switching/main.cpp | 2 +- arch/x86_64/src/kernel/cpu/jmp.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 35a6121..bf150a3 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -354,8 +354,8 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 -.global segment_register_reload_pointer -segment_register_reload_pointer: +.global reload_segment_register +reload_segment_register: xor %rax, %rax mov %rax, %ss mov %rax, %ds @@ -366,7 +366,7 @@ segment_register_reload_pointer: ret _transition_to_long_mode: - //call segment_register_reload_pointer + //call reload_segment_register xor %rax, %rax mov %rax, %ss diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index c3c0cf0..5d19f23 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -15,7 +15,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::segment_selector segment_selector{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{boot::segment_register_reload_pointer, segment_selector}; + kernel::cpu::far_pointer pointer{boot::reload_segment_register, segment_selector}; kernel::cpu::jmp(pointer); // Load task state segment descriptor from the last element in the global descriptor table, done by calculating diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp index 205c4a9..0c94693 100644 --- a/arch/x86_64/src/kernel/cpu/jmp.cpp +++ b/arch/x86_64/src/kernel/cpu/jmp.cpp @@ -2,13 +2,13 @@ namespace teachos::arch::kernel::cpu { - auto jmp(uint64_t address) -> void + auto jmp(std::size_t address) -> void { asm volatile("jmp *%[input]" : /* no output from call */ : [input] "r"(address)); } auto jmp(far_pointer pointer) -> void { - asm volatile("jmp *%[input]" : /* no output from call */ : [input] "m"(pointer)); + asm volatile("rex64 ljmp *%[input]" : /* no output from call */ : [input] "m"(pointer)); } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From fbd1ebe4f7c5985554fdca7c7fc05de15d47dd3a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 28 Mar 2025 18:35:28 +0100 Subject: gdt: fix reload of GDT The core problems were/are the following: - The flags of the segments were not entirely correct. Please recheck them against the spec! - The GDT pointer did not contain the address of the first (null) GTD entry, but the address of the stl::vector containing the GDT entries. - The far pointer must consist of: - the address to jump to - the byte index into the GDT for the desired segement descriptor to be loaded into CS. - The type of the "dummy" function we jump to was wrong (it's a function, we should declare it as such). - We cannot enable interrupts right now, since we die with a triple fault. This is caused by some initia fault which seems to lead to a general protection fault, which then triple faults since we cannot find the IDT. Some FIXMEs have been added to the code. Please look at them carefully and compare things against the specs. --- arch/x86_64/src/boot/boot.s | 3 +++ arch/x86_64/src/context_switching/main.cpp | 25 +++++++++++----------- .../global_descriptor_table.cpp | 8 ++++--- .../global_descriptor_table_pointer.cpp | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index bf150a3..108dbe5 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -356,6 +356,9 @@ prepare_page_maps: .global reload_segment_register reload_segment_register: + // FIXME: maybe we should set the actually correct values here. We'd need to communicate them down from C++. + // Alternatively, we could probably implement this as a [[gnu::naked]] function in C++, to have easier access to + // arguments and symbols. Maybe later. xor %rax, %rax mov %rax, %ss mov %rax, %ds diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 5d19f23..a5bd3fb 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -13,22 +13,21 @@ namespace teachos::arch::context_switching decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table(); - interrupt_descriptor_table::segment_selector segment_selector{ - 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{boot::reload_segment_register, segment_selector}; - kernel::cpu::jmp(pointer); + kernel::cpu::far_pointer pointer{&boot::reload_segment_register, 1 * sizeof(segment_descriptor_table::segment_descriptor)}; + asm volatile("rex64 lcall *%[far_function_pointer]" : : [far_function_pointer] "m" (pointer)); - // 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 = - (global_descriptor_table.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); - kernel::cpu::load_task_register(tss_selector); + // // 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 = + // (global_descriptor_table.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); + // kernel::cpu::load_task_register(tss_selector); - auto const stored_task_register = kernel::cpu::store_task_register(); - arch::exception_handling::assert(tss_selector == stored_task_register, - "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); + // auto const stored_task_register = kernel::cpu::store_task_register(); + // arch::exception_handling::assert(tss_selector == stored_task_register, + // "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); - kernel::cpu::set_interrupt_flag(); + // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP. Maybe because no IDT is loaded? Maybe our boot code segment is not set up correctly? + // kernel::cpu::set_interrupt_flag(); descriptor_tables tables = {global_descriptor_table, interrupt_descriptor_table}; return tables; 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 e6a489c..37ee778 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 @@ -20,12 +20,14 @@ namespace teachos::arch::context_switching::segment_descriptor_table uint8_t gdt_flags_bits = gdt_flags::GRANULARITY; if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) { - gdt_flags_bits |= gdt_flags::LENGTH; + gdt_flags_bits |= gdt_flags::LONG_MODE; access_level_bits |= access_byte::CODE_SEGMENT | access_byte::READABLE; } else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) { - gdt_flags_bits |= gdt_flags::UPPER_BOUND; + gdt_flags_bits |= 1 << 2; + // FIXME: Look at those bit flags, something seems off. + // gdt_flags_bits |= gdt_flags::UPPER_BOUND; access_level_bits |= access_byte::WRITABLE; } @@ -78,7 +80,7 @@ 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((gdt.size() * sizeof(segment_descriptor)) - 1), - &gdt}; + gdt.data()}; kernel::cpu::load_global_descriptor_table(gdt_pointer); auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); 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 132565f..a4a5de8 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 @@ -3,7 +3,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table { global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, - global_descriptor_table * address) + segment_descriptor * address) : table_length(table_length) , address(address) { -- cgit v1.2.3 From aba154ad01fc0e1e1274f2582b1493e78daa2559 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 29 Mar 2025 14:47:04 +0000 Subject: fix gdt segments, improve idt and trial&error for triple fault --- arch/x86_64/src/boot/boot.s | 11 +------- .../interrupt_descriptor_table/gate_descriptor.cpp | 2 ++ .../interrupt_descriptor_table.cpp | 14 ++++++---- .../interrupt_descriptor_table_pointer.cpp | 2 +- arch/x86_64/src/context_switching/main.cpp | 30 +++++++++++++--------- .../global_descriptor_table.cpp | 5 +--- .../generic_interrupt_handler.cpp | 14 ++++++++++ 7 files changed, 46 insertions(+), 32 deletions(-) create mode 100644 arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 108dbe5..38a8af4 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -197,10 +197,8 @@ _start: call enable_paging call enable_sse - cli /* Clears the interrupt flag during the GDT setup */ lgdt (global_descriptor_table_pointer) jmp $global_descriptor_table_code, $_transition_to_long_mode - /* The interrupt flag is set in cpp after setting up the GDT */ call halt @@ -369,14 +367,7 @@ reload_segment_register: ret _transition_to_long_mode: - //call reload_segment_register - - xor %rax, %rax - mov %rax, %ss - mov %rax, %ds - mov %rax, %es - mov %rax, %fs - mov %rax, %gs + call reload_segment_register movl $0xb8000, (vga_buffer_pointer) diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp index 28f289c..d86c459 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp @@ -8,6 +8,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table , _ist(flags >> 32U) , _flags(flags >> 40U) , _offset_2(flags >> 48U) + , _offset_3(flags >> 64U) { // Nothing to do. } @@ -18,6 +19,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table , _ist(ist) , _flags(flags) , _offset_2(offset >> 16U) + , _offset_3(offset >> 48U) { // Nothing to do. } diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index ddc098e..1c1de68 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -1,20 +1,24 @@ #include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/interrupt_handling/generic_interrupt_handler.hpp" #include "arch/kernel/cpu/idtr.hpp" namespace teachos::arch::context_switching::interrupt_descriptor_table { namespace { + auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { - uint64_t offset = 0U; + // @MTO: This address resolution is most certainly wrong -> numbers in dbg seem off (offset_3 = 0) + uint64_t offset = reinterpret_cast(&interrupt_handling::generic_interrupt_handler); segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; ist_offset ist{0U}; - idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL}; - gate_descriptor gate_descriptor{selector, ist, flags, offset}; - return interrupt_descriptor_table{gate_descriptor}; + idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::PRESENT}; + gate_descriptor descriptor{selector, ist, flags, offset}; + + return interrupt_descriptor_table{descriptor}; } } // namespace @@ -24,7 +28,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table static auto idt = create_interrupt_descriptor_table(); interrupt_descriptor_table_pointer idt_pointer{static_cast((idt.size() * sizeof(gate_descriptor)) - 1), - &idt}; + idt.data()}; kernel::cpu::load_interrupt_descriptor_table(idt_pointer); auto const stored_gdt_pointer = kernel::cpu::store_interrupt_descriptor_table(); diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp index 981944d..7bcbae6 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp @@ -3,7 +3,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { interrupt_descriptor_table_pointer::interrupt_descriptor_table_pointer(uint16_t table_length, - interrupt_descriptor_table * address) + gate_descriptor * address) : table_length(table_length) , address(address) { diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index a5bd3fb..f449a3a 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -10,24 +10,30 @@ namespace teachos::arch::context_switching { auto initialize_descriptor_tables() -> descriptor_tables { + kernel::cpu::clear_interrupt_flag(); decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table(); - kernel::cpu::far_pointer pointer{&boot::reload_segment_register, 1 * sizeof(segment_descriptor_table::segment_descriptor)}; - asm volatile("rex64 lcall *%[far_function_pointer]" : : [far_function_pointer] "m" (pointer)); + kernel::cpu::far_pointer pointer{&boot::reload_segment_register, + 1 * sizeof(segment_descriptor_table::segment_descriptor)}; + asm volatile("rex64 lcall *%[far_function_pointer]" : : [far_function_pointer] "m"(pointer)); - // // 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 = - // (global_descriptor_table.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); - // kernel::cpu::load_task_register(tss_selector); + // 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 = + (global_descriptor_table.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); + kernel::cpu::load_task_register(tss_selector); - // auto const stored_task_register = kernel::cpu::store_task_register(); - // arch::exception_handling::assert(tss_selector == stored_task_register, - // "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); + auto const stored_task_register = kernel::cpu::store_task_register(); + arch::exception_handling::assert(tss_selector == stored_task_register, + "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); - // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP. Maybe because no IDT is loaded? Maybe our boot code segment is not set up correctly? - // kernel::cpu::set_interrupt_flag(); + // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP + // and triple fault. + + // @MTO: SOMETIMES i get past a breakpoint here???? seems to happen when i actually pause before (f.e. inside the + // idt). NEVER happened when stepping through quickly. Can you reproduce this? + kernel::cpu::set_interrupt_flag(); descriptor_tables tables = {global_descriptor_table, interrupt_descriptor_table}; return tables; 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 37ee778..d9ad91c 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 @@ -17,17 +17,14 @@ namespace teachos::arch::context_switching::segment_descriptor_table { uint8_t access_level_bits = access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT | *reinterpret_cast(&access_level); - uint8_t gdt_flags_bits = gdt_flags::GRANULARITY; + uint8_t gdt_flags_bits = gdt_flags::GRANULARITY | gdt_flags::LONG_MODE; if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) { - gdt_flags_bits |= gdt_flags::LONG_MODE; access_level_bits |= access_byte::CODE_SEGMENT | access_byte::READABLE; } else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) { gdt_flags_bits |= 1 << 2; - // FIXME: Look at those bit flags, something seems off. - // gdt_flags_bits |= gdt_flags::UPPER_BOUND; access_level_bits |= access_byte::WRITABLE; } diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp new file mode 100644 index 0000000..68b4568 --- /dev/null +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -0,0 +1,14 @@ +#include "arch/interrupt_handling/generic_interrupt_handler.hpp" + +#include "arch/video/vga/text.hpp" + +namespace teachos::arch::interrupt_handling +{ + + [[gnu::interrupt]] + auto generic_interrupt_handler(interrupt_frame * frame) -> void + { + (void)frame; + video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); + } +} // namespace teachos::arch::interrupt_handling \ No newline at end of file -- cgit v1.2.3 From 8d16dcb672c4b5f4b0a12ef2eac3486f1b2bb316 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 29 Mar 2025 14:47:23 +0000 Subject: remove empty line --- arch/x86_64/src/context_switching/main.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index f449a3a..008da2f 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -30,7 +30,6 @@ namespace teachos::arch::context_switching // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP // and triple fault. - // @MTO: SOMETIMES i get past a breakpoint here???? seems to happen when i actually pause before (f.e. inside the // idt). NEVER happened when stepping through quickly. Can you reproduce this? kernel::cpu::set_interrupt_flag(); -- cgit v1.2.3 From abe7bd7480c8f4e1e30b9f0f3b98966222817f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 31 Mar 2025 10:38:53 +0000 Subject: Clean up global descriptor table initalization --- .../interrupt_descriptor_table/gate_descriptor.cpp | 2 - .../interrupt_descriptor_table.cpp | 31 +++++------ arch/x86_64/src/context_switching/main.cpp | 23 ++++----- .../global_descriptor_table.cpp | 60 +++++++++++++--------- .../generic_interrupt_handler.cpp | 2 +- arch/x86_64/src/kernel/cpu/jmp.cpp | 2 +- 6 files changed, 60 insertions(+), 60 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp index d86c459..28f289c 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp @@ -8,7 +8,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table , _ist(flags >> 32U) , _flags(flags >> 40U) , _offset_2(flags >> 48U) - , _offset_3(flags >> 64U) { // Nothing to do. } @@ -19,7 +18,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table , _ist(ist) , _flags(flags) , _offset_2(offset >> 16U) - , _offset_3(offset >> 48U) { // Nothing to do. } diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 1c1de68..62b116b 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -6,26 +6,23 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { - namespace + auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table & { + // @MTO: This address resolution is most certainly wrong -> numbers in dbg seem off (offset_3 = 0) + uint64_t offset = reinterpret_cast(&interrupt_handling::generic_interrupt_handler); + segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; + ist_offset ist{0U}; + idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::PRESENT}; + gate_descriptor descriptor{selector, ist, flags, offset}; - auto create_interrupt_descriptor_table() -> interrupt_descriptor_table - { - // @MTO: This address resolution is most certainly wrong -> numbers in dbg seem off (offset_3 = 0) - uint64_t offset = reinterpret_cast(&interrupt_handling::generic_interrupt_handler); - segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; - ist_offset ist{0U}; - idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::PRESENT}; - gate_descriptor descriptor{selector, ist, flags, offset}; - - return interrupt_descriptor_table{descriptor}; - } - } // namespace + // Interrupt Descriptor Table needs to be kept alive + static interrupt_descriptor_table interrupt_descriptor_table{descriptor}; + return interrupt_descriptor_table; + } - auto initialize_interrupt_descriptor_table() -> interrupt_descriptor_table & + auto update_interrupt_descriptor_table_register() -> void { - // Interrupt Descriptor Table needs to be kept alive - static auto idt = create_interrupt_descriptor_table(); + static auto idt = get_or_create_interrupt_descriptor_table(); interrupt_descriptor_table_pointer idt_pointer{static_cast((idt.size() * sizeof(gate_descriptor)) - 1), idt.data()}; @@ -35,7 +32,5 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table arch::exception_handling::assert( idt_pointer == stored_gdt_pointer, "[Interrupt Descriptor Table] Loaded IDTR value is not the same as the stored value."); - - return idt; } } // 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 008da2f..db04b52 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -11,22 +11,16 @@ namespace teachos::arch::context_switching auto initialize_descriptor_tables() -> descriptor_tables { kernel::cpu::clear_interrupt_flag(); - decltype(auto) global_descriptor_table = segment_descriptor_table::initialize_global_descriptor_table(); - decltype(auto) interrupt_descriptor_table = interrupt_descriptor_table::initialize_interrupt_descriptor_table(); - kernel::cpu::far_pointer pointer{&boot::reload_segment_register, - 1 * sizeof(segment_descriptor_table::segment_descriptor)}; - asm volatile("rex64 lcall *%[far_function_pointer]" : : [far_function_pointer] "m"(pointer)); + segment_descriptor_table::update_global_descriptor_table_register(); + interrupt_descriptor_table::update_interrupt_descriptor_table_register(); - // 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 = - (global_descriptor_table.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); - kernel::cpu::load_task_register(tss_selector); + interrupt_descriptor_table::segment_selector segment_selector{ + 2U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + kernel::cpu::far_pointer pointer{&boot::reload_segment_register, segment_selector}; + kernel::cpu::jmp(pointer); - auto const stored_task_register = kernel::cpu::store_task_register(); - arch::exception_handling::assert(tss_selector == stored_task_register, - "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); + segment_descriptor_table::update_task_state_segment_register(); // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP // and triple fault. @@ -34,7 +28,8 @@ namespace teachos::arch::context_switching // idt). NEVER happened when stepping through quickly. Can you reproduce this? kernel::cpu::set_interrupt_flag(); - descriptor_tables tables = {global_descriptor_table, interrupt_descriptor_table}; + descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), + interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; return tables; } } // namespace teachos::arch::context_switching 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 d9ad91c..346db9e 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 @@ -24,7 +24,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table } else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) { - gdt_flags_bits |= 1 << 2; + gdt_flags_bits |= gdt_flags::UPPER_BOUND; access_level_bits |= access_byte::WRITABLE; } @@ -46,33 +46,33 @@ namespace teachos::arch::context_switching::segment_descriptor_table TSS_LIMIT}; return tss_descriptor; } + } // namespace - auto create_global_descriptor_table() -> global_descriptor_table - { - segment_descriptor const null_segment{0}; - segment_descriptor const kernel_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor const kernel_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor const user_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); - segment_descriptor const user_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); + auto get_or_create_global_descriptor_table() -> global_descriptor_table & + { + segment_descriptor const null_segment{0}; + segment_descriptor const kernel_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor const kernel_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor const user_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); + segment_descriptor 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_task_state_segment_descriptor(tss); + // Task State Segment needs to be kept alive + static auto tss = new task_state_segment(); + segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); - global_descriptor_table const global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment, tss_descriptor}; - return global_descriptor_table; - } - } // namespace + // Global Descriptor Table needs to be kept alive + static global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment, tss_descriptor}; + return global_descriptor_table; + } - auto initialize_global_descriptor_table() -> global_descriptor_table & + auto update_global_descriptor_table_register() -> void { - // Global Descriptor Table needs to be kept alive - static auto gdt = create_global_descriptor_table(); + decltype(auto) gdt = get_or_create_global_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. @@ -84,8 +84,20 @@ namespace teachos::arch::context_switching::segment_descriptor_table arch::exception_handling::assert( gdt_pointer == stored_gdt_pointer, "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); + } + + auto update_task_state_segment_register() -> void + { + decltype(auto) gdt = get_or_create_global_descriptor_table(); + + // 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 = (gdt.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); + kernel::cpu::load_task_register(tss_selector); - return gdt; + auto const stored_task_register = kernel::cpu::store_task_register(); + arch::exception_handling::assert(tss_selector == stored_task_register, + "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); } } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp index 68b4568..2f599e5 100644 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -11,4 +11,4 @@ namespace teachos::arch::interrupt_handling (void)frame; video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); } -} // namespace teachos::arch::interrupt_handling \ No newline at end of file +} // namespace teachos::arch::interrupt_handling diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp index 0c94693..2833219 100644 --- a/arch/x86_64/src/kernel/cpu/jmp.cpp +++ b/arch/x86_64/src/kernel/cpu/jmp.cpp @@ -9,6 +9,6 @@ namespace teachos::arch::kernel::cpu auto jmp(far_pointer pointer) -> void { - asm volatile("rex64 ljmp *%[input]" : /* no output from call */ : [input] "m"(pointer)); + asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From e8fb1d771d9aa4d1cb5b18cd0483c7e5731aeecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 31 Mar 2025 13:18:56 +0000 Subject: Improve create_segment readability --- .../interrupt_descriptor_table/idt_flags.cpp | 2 + .../interrupt_descriptor_table.cpp | 28 ++++++---- .../segment_selector.cpp | 2 + arch/x86_64/src/context_switching/main.cpp | 2 - .../segment_descriptor_table/access_byte.cpp | 2 + .../segment_descriptor_table/gdt_flags.cpp | 2 + .../global_descriptor_table.cpp | 62 ++++++++++++---------- 7 files changed, 60 insertions(+), 40 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp index e7379ef..d36a4c1 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp @@ -12,4 +12,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { return (std::bitset<8U>{_flags} & other) == other; } + + auto idt_flags::operator|=(std::bitset<8U> other) -> void { _flags |= other.to_ulong(); } } // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 62b116b..db3351e 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -6,18 +6,28 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { - auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table & + namespace { - // @MTO: This address resolution is most certainly wrong -> numbers in dbg seem off (offset_3 = 0) - uint64_t offset = reinterpret_cast(&interrupt_handling::generic_interrupt_handler); - segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; - ist_offset ist{0U}; - idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::PRESENT}; - gate_descriptor descriptor{selector, ist, flags, offset}; + auto create_interrupt_descriptor_table() -> interrupt_descriptor_table + { + // @MTO: This address resolution is most certainly wrong -> numbers in dbg seem off (offset_3 = 0) + uint64_t offset = reinterpret_cast(&interrupt_handling::generic_interrupt_handler); + segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; + ist_offset ist{0U}; + idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::PRESENT}; + gate_descriptor descriptor{selector, ist, flags, offset}; + + // Interrupt Descriptor Table needs to be kept alive + static interrupt_descriptor_table interrupt_descriptor_table{descriptor}; + return interrupt_descriptor_table; + } + } // namespace + auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table & + { // Interrupt Descriptor Table needs to be kept alive - static interrupt_descriptor_table interrupt_descriptor_table{descriptor}; - return interrupt_descriptor_table; + static interrupt_descriptor_table idt = create_interrupt_descriptor_table(); + return idt; } auto update_interrupt_descriptor_table_register() -> void 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 494e50f..62aed9b 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 @@ -13,4 +13,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { return (std::bitset<3U>{_flags} & other) == other; } + + auto segment_selector::operator|=(std::bitset<3U> other) -> void { _flags |= other.to_ulong(); } } // 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 db04b52..2b853ec 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -24,8 +24,6 @@ namespace teachos::arch::context_switching // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP // and triple fault. - // @MTO: SOMETIMES i get past a breakpoint here???? seems to happen when i actually pause before (f.e. inside the - // idt). NEVER happened when stepping through quickly. Can you reproduce this? kernel::cpu::set_interrupt_flag(); descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp index 34a10f1..e31e021 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp @@ -12,4 +12,6 @@ namespace teachos::arch::context_switching::segment_descriptor_table { return (std::bitset<8U>{_flags} & other) == other; } + + auto access_byte::operator|=(std::bitset<8U> other) -> void { _flags |= other.to_ulong(); } } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp index 9885bda..e444a24 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp @@ -15,4 +15,6 @@ namespace teachos::arch::context_switching::segment_descriptor_table } auto gdt_flags::get_limit() const -> std::bitset<4U> { return std::bitset<4U>{_limit_2}; } + + auto gdt_flags::operator|=(std::bitset<4U> other) -> void { _flags |= other.to_ulong(); } } // namespace teachos::arch::context_switching::segment_descriptor_table 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 346db9e..a497632 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 @@ -11,28 +11,26 @@ 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 { - uint8_t access_level_bits = - access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT | *reinterpret_cast(&access_level); - uint8_t gdt_flags_bits = gdt_flags::GRANULARITY | gdt_flags::LONG_MODE; + uint64_t const base = 0x0; + std::bitset<20U> const limit{0xFFFFF}; + gdt_flags flags{gdt_flags::GRANULARITY, limit}; + + access_level |= access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT; if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) { - access_level_bits |= access_byte::CODE_SEGMENT | access_byte::READABLE; + flags |= gdt_flags::LONG_MODE; + access_level |= access_byte::CODE_SEGMENT | access_byte::READABLE; } else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) { - gdt_flags_bits |= gdt_flags::UPPER_BOUND; - access_level_bits |= access_byte::WRITABLE; + flags |= gdt_flags::UPPER_BOUND; + access_level |= access_byte::WRITABLE; } - uint64_t const base = 0x0; - std::bitset<20U> const limit{0xFFFFF}; - access_byte const access_byte{access_level_bits}; - gdt_flags const gdt_flags{gdt_flags_bits, limit}; - segment_descriptor const segment_descriptor{access_byte, gdt_flags, base, limit}; + segment_descriptor const segment_descriptor{access_level, flags, base, limit}; return segment_descriptor; } @@ -46,28 +44,34 @@ namespace teachos::arch::context_switching::segment_descriptor_table TSS_LIMIT}; return tss_descriptor; } + + auto create_global_descriptor_table() -> global_descriptor_table + { + segment_descriptor const null_segment{0}; + segment_descriptor const kernel_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor const kernel_data_segment = + create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); + segment_descriptor const user_code_segment = + create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); + segment_descriptor 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_task_state_segment_descriptor(tss); + + global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, + user_code_segment, user_data_segment, tss_descriptor}; + return global_descriptor_table; + } } // namespace auto get_or_create_global_descriptor_table() -> global_descriptor_table & { - segment_descriptor const null_segment{0}; - segment_descriptor const kernel_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor const kernel_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor const user_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); - segment_descriptor 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_task_state_segment_descriptor(tss); - // Global Descriptor Table needs to be kept alive - static global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment, tss_descriptor}; - return global_descriptor_table; + static global_descriptor_table gdt = create_global_descriptor_table(); + return gdt; } auto update_global_descriptor_table_register() -> void -- cgit v1.2.3 From 40cfa485cc2c9e344a0386419ed55c123312ec32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 31 Mar 2025 15:20:27 +0000 Subject: Add missing flag to idt entry. --- .../interrupt_descriptor_table.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index db3351e..b520a57 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -10,15 +10,20 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { - // @MTO: This address resolution is most certainly wrong -> numbers in dbg seem off (offset_3 = 0) - uint64_t offset = reinterpret_cast(&interrupt_handling::generic_interrupt_handler); - segment_selector selector{0U, segment_selector::REQUEST_LEVEL_KERNEL}; + // TODO: See 7.14 Vol. 3A Page 3299 Intel Manual, still crashes from time to time on setting interrupt flag? + // Probably an interrupt is generated but the interrupt descriptor table is not in a valid form and does not + // handle the interrupt. + interrupt_descriptor_table interrupt_descriptor_table{256}; + + uint64_t offset = 0U; + segment_selector selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}; ist_offset ist{0U}; - idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::PRESENT}; - gate_descriptor descriptor{selector, ist, flags, offset}; + idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}; - // Interrupt Descriptor Table needs to be kept alive - static interrupt_descriptor_table interrupt_descriptor_table{descriptor}; + for (std::size_t i = 0; i < 256; i++) + { + interrupt_descriptor_table.at(i) = {selector, ist, flags, offset}; + } return interrupt_descriptor_table; } } // namespace @@ -32,7 +37,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table auto update_interrupt_descriptor_table_register() -> void { - static auto idt = get_or_create_interrupt_descriptor_table(); + decltype(auto) idt = get_or_create_interrupt_descriptor_table(); interrupt_descriptor_table_pointer idt_pointer{static_cast((idt.size() * sizeof(gate_descriptor)) - 1), idt.data()}; -- cgit v1.2.3 From fc4a2306b803ccfc27f1bdc4a831176a5278a9d5 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Wed, 2 Apr 2025 09:57:54 +0000 Subject: fix interrupt handler and idt --- .../interrupt_descriptor_table.cpp | 13 ++++++------- arch/x86_64/src/context_switching/main.cpp | 2 -- .../src/interrupt_handling/generic_interrupt_handler.cpp | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index b520a57..82114b4 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -10,20 +10,19 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { - // TODO: See 7.14 Vol. 3A Page 3299 Intel Manual, still crashes from time to time on setting interrupt flag? - // Probably an interrupt is generated but the interrupt descriptor table is not in a valid form and does not - // handle the interrupt. - interrupt_descriptor_table interrupt_descriptor_table{256}; + // Only account for the reserved Vectors for now (0 - 31) + interrupt_descriptor_table interrupt_descriptor_table{32}; - uint64_t offset = 0U; - segment_selector selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}; + uint64_t offset = reinterpret_cast(interrupt_handling::generic_interrupt_handler); + segment_selector selector{2U, segment_selector::REQUEST_LEVEL_KERNEL}; ist_offset ist{0U}; idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}; - for (std::size_t i = 0; i < 256; i++) + for (std::size_t i = 0; i < 32; i++) { interrupt_descriptor_table.at(i) = {selector, ist, flags, offset}; } + return interrupt_descriptor_table; } } // namespace diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 2b853ec..ac53735 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -22,8 +22,6 @@ namespace teachos::arch::context_switching segment_descriptor_table::update_task_state_segment_register(); - // FIXME: We currently cannot enable interrupts, since for some reason, we will later run into what looks like a GP - // and triple fault. kernel::cpu::set_interrupt_flag(); descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp index 2f599e5..4392b04 100644 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -5,7 +5,7 @@ namespace teachos::arch::interrupt_handling { - [[gnu::interrupt]] + [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] auto generic_interrupt_handler(interrupt_frame * frame) -> void { (void)frame; -- cgit v1.2.3 From 8b66e4cd1d1487fefbae459f556396db61497a6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 4 Apr 2025 15:05:59 +0000 Subject: Multiplication by two for segment selector index --- .../context_switching/interrupt_descriptor_table/segment_selector.cpp | 2 +- arch/x86_64/src/context_switching/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src') 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 62aed9b..b1b316d 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 @@ -4,7 +4,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { segment_selector::segment_selector(uint16_t index, uint8_t flags) : _flags(flags) - , _index(index) + , _index(index * 2U) { // Nothing to do. } diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index ac53735..6614065 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -16,7 +16,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::update_interrupt_descriptor_table_register(); interrupt_descriptor_table::segment_selector segment_selector{ - 2U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; kernel::cpu::far_pointer pointer{&boot::reload_segment_register, segment_selector}; kernel::cpu::jmp(pointer); -- cgit v1.2.3 From c01d080bdc6bd843e840e4834424fe587286b274 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 5 Apr 2025 12:04:12 +0000 Subject: fix segment_selector --- .../interrupt_descriptor_table/interrupt_descriptor_table.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 82114b4..9b62110 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -14,7 +14,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table interrupt_descriptor_table interrupt_descriptor_table{32}; uint64_t offset = reinterpret_cast(interrupt_handling::generic_interrupt_handler); - segment_selector selector{2U, segment_selector::REQUEST_LEVEL_KERNEL}; + segment_selector selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}; ist_offset ist{0U}; idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}; -- cgit v1.2.3 From a8852f91967a7e55e62e30f5cc07d076092b8b78 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 5 Apr 2025 15:27:20 +0000 Subject: add wip context switch to user mode --- arch/x86_64/src/boot/boot.s | 11 +------- arch/x86_64/src/context_switching/main.cpp | 4 +-- arch/x86_64/src/kernel/cpu/segment_register.cpp | 34 ++++++++++++++++++++++++ arch/x86_64/src/kernel/cpu/ss.cpp | 16 ----------- arch/x86_64/src/kernel/main.cpp | 35 +++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 28 deletions(-) create mode 100644 arch/x86_64/src/kernel/cpu/segment_register.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/ss.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 38a8af4..7932045 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -352,11 +352,7 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 -.global reload_segment_register -reload_segment_register: - // FIXME: maybe we should set the actually correct values here. We'd need to communicate them down from C++. - // Alternatively, we could probably implement this as a [[gnu::naked]] function in C++, to have easier access to - // arguments and symbols. Maybe later. +_transition_to_long_mode: xor %rax, %rax mov %rax, %ss mov %rax, %ds @@ -364,11 +360,6 @@ reload_segment_register: mov %rax, %fs mov %rax, %gs - ret - -_transition_to_long_mode: - call reload_segment_register - movl $0xb8000, (vga_buffer_pointer) call _init diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 6614065..124df93 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,9 +1,9 @@ #include "arch/context_switching/main.hpp" -#include "arch/boot/pointers.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/jmp.hpp" +#include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" namespace teachos::arch::context_switching @@ -17,7 +17,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::segment_selector segment_selector{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{&boot::reload_segment_register, segment_selector}; + kernel::cpu::far_pointer pointer{&kernel::cpu::reload_segment_registers, segment_selector}; kernel::cpu::jmp(pointer); segment_descriptor_table::update_task_state_segment_register(); diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp new file mode 100644 index 0000000..f70c558 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -0,0 +1,34 @@ +#include "arch/kernel/cpu/segment_register.hpp" + +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" + +namespace teachos::arch::kernel::cpu +{ + [[gnu::naked]] + auto reload_segment_registers() -> void + { + asm volatile("xor %rax, %rax\n" + "mov %rax, %ss\n" + "mov %rax, %ds\n" + "mov %rax, %es\n" + "mov %rax, %fs\n" + "mov %rax, %gs\n" + "ret"); + } + + [[gnu::naked]] + auto set_segment_registers(context_switching::interrupt_descriptor_table::segment_selector segment_selector) -> void + { + asm volatile("xor %%rax, %%rax\n" + "mov %[input], %%ax\n" + "mov %%rax, %%ss\n" + "mov %%rax, %%ds\n" + "mov %%rax, %%es\n" + "mov %%rax, %%fs\n" + "mov %%rax, %%gs\n" + "ret" + : /* No output from call */ + : [input] "m"(segment_selector)); + } + +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/ss.cpp b/arch/x86_64/src/kernel/cpu/ss.cpp deleted file mode 100644 index 0978eca..0000000 --- a/arch/x86_64/src/kernel/cpu/ss.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "arch/kernel/cpu/ss.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto read_ss() -> context_switching::interrupt_descriptor_table::segment_selector - { - context_switching::interrupt_descriptor_table::segment_selector segment_selector{}; - asm volatile("mov %%ss, %[output]" : [output] "=m"(segment_selector)); - return segment_selector; - } - - auto write_ss(context_switching::interrupt_descriptor_table::segment_selector selector) -> void - { - asm volatile("mov %[input], %%ss" : /* no output from call */ : [input] "m"(selector)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 7782d30..7d4173e 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/boot/pointers.hpp" +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" #include "arch/context_switching/main.hpp" #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/jmp.hpp" +#include "arch/kernel/cpu/segment_register.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/main.hpp" @@ -49,6 +51,23 @@ namespace teachos::arch::kernel delete test9; } + [[gnu::naked]] + auto push_code_segment(context_switching::interrupt_descriptor_table::segment_selector segment_selector) -> void + { + asm volatile("push %%rbp\n" + "push %[input]" + : /* No output from call */ + : [input] "m"(segment_selector)); + } + + [[gnu::naked]] + auto iret() -> void + { + asm volatile("iret" + : /* No output from call */ + : /* No input to call */); + } + auto main() -> void { video::vga::text::clear(); @@ -64,6 +83,22 @@ namespace teachos::arch::kernel heap_test(); decltype(auto) descriptor_tables = context_switching::initialize_descriptor_tables(); + + // - Clear NT flag in EFLAGS register (for far return) + + // - Push return instruction pointer + // - Push return code segment selector + context_switching::interrupt_descriptor_table::segment_selector user_code_segment_selector{ + 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + push_code_segment(user_code_segment_selector); + + context_switching::interrupt_descriptor_table::segment_selector user_data_segment_selector{ + 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + kernel::cpu::set_segment_registers(user_data_segment_selector); + + // IRET + iret(); + (void)descriptor_tables; } } // namespace teachos::arch::kernel -- cgit v1.2.3 From 350aedae0e50749f9821ac7dc6b8316cf35f24bb Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 6 Apr 2025 07:47:27 +0000 Subject: wip context switch in asm --- arch/x86_64/src/boot/boot.s | 29 +++++++++++++++++++++++++++++ arch/x86_64/src/kernel/main.cpp | 31 ++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 11 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 7932045..85ae1a1 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -352,6 +352,35 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 +.global context_switch +context_switch: + // ring 3 data with bottom 2 bits set for ring 3 + mov $((4 * 16) | 3), %rax + mov %rax, %ds + mov %rax, %es + mov %rax, %fs + mov %rax, %gs + // SS is handled by iret https://wiki.osdev.org/Getting_to_Ring_3 + + // set up the stack frame iret expects + mov %rsp, %rax + // user data selector + push $((4 * 16) | 3) + // current exp + push %rax + // push eflags + pushf + // push code selector (ring 3 code with bottom 2 bits set for ring 3) + push $((3 * 16) | 3) + // instruction address to return to + push test_function + + iret + +test_function: + cli + ret + _transition_to_long_mode: xor %rax, %rax mov %rax, %ss diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 7d4173e..52799f0 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -52,12 +52,24 @@ namespace teachos::arch::kernel } [[gnu::naked]] - auto push_code_segment(context_switching::interrupt_descriptor_table::segment_selector segment_selector) -> void + auto push_code_segment(context_switching::interrupt_descriptor_table::segment_selector segment_selector_a, + context_switching::interrupt_descriptor_table::segment_selector segment_selector_b) -> void { asm volatile("push %%rbp\n" "push %[input]" : /* No output from call */ - : [input] "m"(segment_selector)); + : [input] "m"(segment_selector_a)); + asm volatile("mov %[input], %%ax\n" + "mov %%ax, %%ss\n" + "mov %%ax, %%ds\n" + "mov %%ax, %%es\n" + "mov %%ax, %%fs\n" + "mov %%ax, %%gs" + : /* No output from call */ + : [input] "m"(segment_selector_b)); + asm volatile("iret" + : /* No output from call */ + : /* No input to call */); } [[gnu::naked]] @@ -88,16 +100,13 @@ namespace teachos::arch::kernel // - Push return instruction pointer // - Push return code segment selector - context_switching::interrupt_descriptor_table::segment_selector user_code_segment_selector{ - 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - push_code_segment(user_code_segment_selector); - - context_switching::interrupt_descriptor_table::segment_selector user_data_segment_selector{ - 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - kernel::cpu::set_segment_registers(user_data_segment_selector); + // context_switching::interrupt_descriptor_table::segment_selector user_code_segment_selector{ + // 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + // context_switching::interrupt_descriptor_table::segment_selector user_data_segment_selector{ + // 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + // push_code_segment(user_code_segment_selector, user_data_segment_selector); - // IRET - iret(); + boot::context_switch(); (void)descriptor_tables; } -- cgit v1.2.3 From 8a23a47425162894141f4eac488fb1f1bb3f7dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 7 Apr 2025 15:42:38 +0000 Subject: Fix naming from jmp to call for Far Call --- arch/x86_64/src/context_switching/main.cpp | 4 ++-- arch/x86_64/src/kernel/cpu/call.cpp | 9 +++++++++ arch/x86_64/src/kernel/cpu/jmp.cpp | 14 -------------- arch/x86_64/src/kernel/main.cpp | 1 - 4 files changed, 11 insertions(+), 17 deletions(-) create mode 100644 arch/x86_64/src/kernel/cpu/call.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/jmp.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 124df93..762445f 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,8 +1,8 @@ #include "arch/context_switching/main.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/jmp.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" @@ -18,7 +18,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::segment_selector segment_selector{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; kernel::cpu::far_pointer pointer{&kernel::cpu::reload_segment_registers, segment_selector}; - kernel::cpu::jmp(pointer); + kernel::cpu::call(pointer); segment_descriptor_table::update_task_state_segment_register(); diff --git a/arch/x86_64/src/kernel/cpu/call.cpp b/arch/x86_64/src/kernel/cpu/call.cpp new file mode 100644 index 0000000..98fa248 --- /dev/null +++ b/arch/x86_64/src/kernel/cpu/call.cpp @@ -0,0 +1,9 @@ +#include "arch/kernel/cpu/call.hpp" + +namespace teachos::arch::kernel::cpu +{ + auto call(far_pointer pointer) -> void + { + asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); + } +} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/jmp.cpp b/arch/x86_64/src/kernel/cpu/jmp.cpp deleted file mode 100644 index 2833219..0000000 --- a/arch/x86_64/src/kernel/cpu/jmp.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "arch/kernel/cpu/jmp.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto jmp(std::size_t address) -> void - { - asm volatile("jmp *%[input]" : /* no output from call */ : [input] "r"(address)); - } - - auto jmp(far_pointer pointer) -> void - { - asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 52799f0..7787f30 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -4,7 +4,6 @@ #include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" #include "arch/context_switching/main.hpp" #include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/jmp.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" -- cgit v1.2.3 From 5a8659adaa54ce9514db72d1e40f33dec88605ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 10 Apr 2025 08:06:50 +0000 Subject: Move interrupt count into seperate variable --- .../interrupt_descriptor_table/interrupt_descriptor_table.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 9b62110..80f01a8 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -8,17 +8,20 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { namespace { + /// @brief Amount of currently reserved interrupt indicies. + /// See https://wiki.osdev.org/Interrupt_Descriptor_Table#IDT_items for more information. + constexpr uint8_t RESERVED_INTERRUPT_COUNT = 32U; + auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { - // Only account for the reserved Vectors for now (0 - 31) - interrupt_descriptor_table interrupt_descriptor_table{32}; + interrupt_descriptor_table interrupt_descriptor_table{RESERVED_INTERRUPT_COUNT}; uint64_t offset = reinterpret_cast(interrupt_handling::generic_interrupt_handler); segment_selector selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}; ist_offset ist{0U}; idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}; - for (std::size_t i = 0; i < 32; i++) + for (std::size_t i = 0; i < interrupt_descriptor_table.size(); i++) { interrupt_descriptor_table.at(i) = {selector, ist, flags, offset}; } -- cgit v1.2.3 From 862d7f33414132cb73f7f3968250a071d78c191b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 10 Apr 2025 08:10:10 +0000 Subject: Replace iret with iretq (64-bit) --- arch/x86_64/src/kernel/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 7787f30..daaf216 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -66,7 +66,7 @@ namespace teachos::arch::kernel "mov %%ax, %%gs" : /* No output from call */ : [input] "m"(segment_selector_b)); - asm volatile("iret" + asm volatile("iretq" : /* No output from call */ : /* No input to call */); } @@ -74,7 +74,7 @@ namespace teachos::arch::kernel [[gnu::naked]] auto iret() -> void { - asm volatile("iret" + asm volatile("iretq" : /* No output from call */ : /* No input to call */); } -- cgit v1.2.3 From c2d22838c0500970f275069f19d2a0bd2a016d1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 10 Apr 2025 09:26:50 +0000 Subject: Also add iretq to boot.s --- arch/x86_64/src/boot/boot.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 85ae1a1..5a49d48 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -375,7 +375,7 @@ context_switch: // instruction address to return to push test_function - iret + iretq test_function: cli -- cgit v1.2.3 From 295f1bc9a29267b72504fffb582a08c2467b1a7f Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 10 Apr 2025 09:32:20 +0000 Subject: fix context_switch function --- arch/x86_64/src/boot/boot.s | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 85ae1a1..139fd1a 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -352,6 +352,10 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 +test_function: + cli + ret + .global context_switch context_switch: // ring 3 data with bottom 2 bits set for ring 3 @@ -366,20 +370,17 @@ context_switch: mov %rsp, %rax // user data selector push $((4 * 16) | 3) - // current exp + // current rsp push %rax // push eflags pushf // push code selector (ring 3 code with bottom 2 bits set for ring 3) push $((3 * 16) | 3) - // instruction address to return to - push test_function - - iret + // push instruction address to return to + lea [test_function], %rax + push %rax -test_function: - cli - ret + iretq _transition_to_long_mode: xor %rax, %rax -- cgit v1.2.3 From 62d7fa83e831e84ea851d97b5c957146880ad69a Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 10 Apr 2025 10:28:46 +0000 Subject: move context_switch function into cpp code --- arch/x86_64/src/boot/boot.s | 30 ---------- arch/x86_64/src/kernel/cpu/segment_register.cpp | 1 - arch/x86_64/src/kernel/main.cpp | 76 ++++++++++++++----------- 3 files changed, 44 insertions(+), 63 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 139fd1a..7932045 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -352,36 +352,6 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 -test_function: - cli - ret - -.global context_switch -context_switch: - // ring 3 data with bottom 2 bits set for ring 3 - mov $((4 * 16) | 3), %rax - mov %rax, %ds - mov %rax, %es - mov %rax, %fs - mov %rax, %gs - // SS is handled by iret https://wiki.osdev.org/Getting_to_Ring_3 - - // set up the stack frame iret expects - mov %rsp, %rax - // user data selector - push $((4 * 16) | 3) - // current rsp - push %rax - // push eflags - pushf - // push code selector (ring 3 code with bottom 2 bits set for ring 3) - push $((3 * 16) | 3) - // push instruction address to return to - lea [test_function], %rax - push %rax - - iretq - _transition_to_long_mode: xor %rax, %rax mov %rax, %ss diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index f70c558..d7857dd 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -21,7 +21,6 @@ namespace teachos::arch::kernel::cpu { asm volatile("xor %%rax, %%rax\n" "mov %[input], %%ax\n" - "mov %%rax, %%ss\n" "mov %%rax, %%ds\n" "mov %%rax, %%es\n" "mov %%rax, %%fs\n" diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index daaf216..ac2591e 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -50,33 +50,48 @@ namespace teachos::arch::kernel delete test9; } - [[gnu::naked]] - auto push_code_segment(context_switching::interrupt_descriptor_table::segment_selector segment_selector_a, - context_switching::interrupt_descriptor_table::segment_selector segment_selector_b) -> void + auto return_function() -> void { - asm volatile("push %%rbp\n" - "push %[input]" - : /* No output from call */ - : [input] "m"(segment_selector_a)); - asm volatile("mov %[input], %%ax\n" - "mov %%ax, %%ss\n" - "mov %%ax, %%ds\n" - "mov %%ax, %%es\n" - "mov %%ax, %%fs\n" - "mov %%ax, %%gs" - : /* No output from call */ - : [input] "m"(segment_selector_b)); - asm volatile("iretq" - : /* No output from call */ - : /* No input to call */); + video::vga::text::write("User Mode!!!", video::vga::text::common_attributes::green_on_black); } + /** + * @brief Switch context into the mode defined in the segment selectors. + * + * Setup the stack IRETQ expects to switch the mode: + * 1. push data selector + * 2. push current stack pointer + * 3. push eflags + * 4. push code segment selector + * 5. push return address + * + * @param data_segment + * @param code_segment + * @param address + */ [[gnu::naked]] - auto iret() -> void + auto switch_context(context_switching::interrupt_descriptor_table::segment_selector data_segment, + context_switching::interrupt_descriptor_table::segment_selector code_segment, uint64_t address) + -> void { - asm volatile("iretq" - : /* No output from call */ - : /* No input to call */); + asm volatile("mov %[data_segment], %%rax\n" + "mov %%rax, %%ds\n" + "mov %%rax, %%es\n" + "mov %%rax, %%fs\n" + "mov %%rax, %%gs\n" + "mov %%rsp, %%rax\n" + + "push %[data_segment]\n" + "push %%rax\n" + "pushfq\n" + "push %[code_segment]\n" + "mov %[return_function], %%rax\n" + "push %%rax\n" + + "iretq\n" + : + : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) + : "rax"); } auto main() -> void @@ -95,17 +110,14 @@ namespace teachos::arch::kernel decltype(auto) descriptor_tables = context_switching::initialize_descriptor_tables(); - // - Clear NT flag in EFLAGS register (for far return) - - // - Push return instruction pointer - // - Push return code segment selector - // context_switching::interrupt_descriptor_table::segment_selector user_code_segment_selector{ - // 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - // context_switching::interrupt_descriptor_table::segment_selector user_data_segment_selector{ - // 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - // push_code_segment(user_code_segment_selector, user_data_segment_selector); + context_switching::interrupt_descriptor_table::segment_selector user_code_segment_selector{ + 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + context_switching::interrupt_descriptor_table::segment_selector user_data_segment_selector{ + 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - boot::context_switch(); + cpu::set_segment_registers(user_data_segment_selector); + switch_context(user_data_segment_selector, user_code_segment_selector, + reinterpret_cast(&return_function)); (void)descriptor_tables; } -- cgit v1.2.3 From dff78de795a89c181e9c94b26db2f16988e8f4d6 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 10 Apr 2025 12:11:55 +0000 Subject: move context_switch function and environment into different directory --- .../segment_selector.cpp | 7 --- arch/x86_64/src/context_switching/main.cpp | 72 ++++++++++++++++++++++ arch/x86_64/src/kernel/cpu/segment_register.cpp | 9 +++ arch/x86_64/src/kernel/main.cpp | 56 +---------------- 4 files changed, 83 insertions(+), 61 deletions(-) (limited to 'arch/x86_64/src') 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 b1b316d..0e29356 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 @@ -2,13 +2,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { - segment_selector::segment_selector(uint16_t index, uint8_t flags) - : _flags(flags) - , _index(index * 2U) - { - // Nothing to do. - } - auto segment_selector::contains_flags(std::bitset<3U> other) const -> bool { return (std::bitset<3U>{_flags} & other) == other; diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 762445f..3efba45 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -5,9 +5,59 @@ #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" +#include "arch/video/vga/text.hpp" namespace teachos::arch::context_switching { + namespace + { + + /** + * @brief Switch context into the mode defined in the segment selectors. + * + * Setup the stack IRETQ expects to switch the mode: + * 1. push data selector + * 2. push current stack pointer + * 3. push eflags + * 4. push code segment selector + * 5. push return address + * + * @param data_segment + * @param code_segment + * @param address + */ + [[gnu::naked]] + auto far_return(context_switching::interrupt_descriptor_table::segment_selector data_segment, + context_switching::interrupt_descriptor_table::segment_selector code_segment, uint64_t address) + -> void + { + asm volatile("mov %[data_segment], %%rax\n" + "mov %%rax, %%ds\n" + "mov %%rax, %%es\n" + "mov %%rax, %%fs\n" + "mov %%rax, %%gs\n" + "mov %%rsp, %%rax\n" + + "push %[data_segment]\n" + "push %%rax\n" + "pushfq\n" + "push %[code_segment]\n" + "mov %[return_function], %%rax\n" + "push %%rax\n" + + "iretq\n" + : + : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) + : "rax"); + } + + constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ + 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ + 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + + } // namespace + auto initialize_descriptor_tables() -> descriptor_tables { kernel::cpu::clear_interrupt_flag(); @@ -28,4 +78,26 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; return tables; } + + auto user_mode_main() -> void + { + auto current_segment = kernel::cpu::read_code_segment_register(); + arch::exception_handling::assert(USER_CODE_SEGMENT_SELECTOR == current_segment, + "[Context Switching] Context switch into user mode not successful"); + + video::vga::text::write("User Mode!!!", video::vga::text::common_attributes::green_on_black); + } + + auto switch_to_user_mode() -> void + { + switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user_mode_main); + } + + auto switch_context(interrupt_descriptor_table::segment_selector data_segment, + interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void + { + kernel::cpu::set_segment_registers(data_segment); + far_return(data_segment, code_segment, reinterpret_cast(return_function)); + } + } // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index d7857dd..9fb7433 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -30,4 +30,13 @@ namespace teachos::arch::kernel::cpu : [input] "m"(segment_selector)); } + auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector + { + context_switching::interrupt_descriptor_table::segment_selector current_value; + asm volatile("mov %%cs, %[output]" : [output] "=r"(current_value)); + return current_value; + } + + auto validate_segment_registers() -> context_switching::interrupt_descriptor_table::segment_selector {} + } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index ac2591e..b69064d 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -50,50 +50,6 @@ namespace teachos::arch::kernel delete test9; } - auto return_function() -> void - { - video::vga::text::write("User Mode!!!", video::vga::text::common_attributes::green_on_black); - } - - /** - * @brief Switch context into the mode defined in the segment selectors. - * - * Setup the stack IRETQ expects to switch the mode: - * 1. push data selector - * 2. push current stack pointer - * 3. push eflags - * 4. push code segment selector - * 5. push return address - * - * @param data_segment - * @param code_segment - * @param address - */ - [[gnu::naked]] - auto switch_context(context_switching::interrupt_descriptor_table::segment_selector data_segment, - context_switching::interrupt_descriptor_table::segment_selector code_segment, uint64_t address) - -> void - { - asm volatile("mov %[data_segment], %%rax\n" - "mov %%rax, %%ds\n" - "mov %%rax, %%es\n" - "mov %%rax, %%fs\n" - "mov %%rax, %%gs\n" - "mov %%rsp, %%rax\n" - - "push %[data_segment]\n" - "push %%rax\n" - "pushfq\n" - "push %[code_segment]\n" - "mov %[return_function], %%rax\n" - "push %%rax\n" - - "iretq\n" - : - : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) - : "rax"); - } - auto main() -> void { video::vga::text::clear(); @@ -109,16 +65,8 @@ namespace teachos::arch::kernel heap_test(); decltype(auto) descriptor_tables = context_switching::initialize_descriptor_tables(); - - context_switching::interrupt_descriptor_table::segment_selector user_code_segment_selector{ - 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - context_switching::interrupt_descriptor_table::segment_selector user_data_segment_selector{ - 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - - cpu::set_segment_registers(user_data_segment_selector); - switch_context(user_data_segment_selector, user_code_segment_selector, - reinterpret_cast(&return_function)); - (void)descriptor_tables; + + context_switching::switch_to_user_mode(); } } // namespace teachos::arch::kernel -- cgit v1.2.3 From 87091e2246d2c4c794d9d6a0c5398ca80d92335a Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 10 Apr 2025 12:29:19 +0000 Subject: add register validation and asserts --- arch/x86_64/src/context_switching/main.cpp | 9 ++++++--- arch/x86_64/src/kernel/cpu/segment_register.cpp | 23 ++++++++++++++++++++++- 2 files changed, 28 insertions(+), 4 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 3efba45..0f2ec93 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -2,6 +2,7 @@ #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" +#include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" @@ -82,10 +83,12 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { auto current_segment = kernel::cpu::read_code_segment_register(); - arch::exception_handling::assert(USER_CODE_SEGMENT_SELECTOR == current_segment, - "[Context Switching] Context switch into user mode not successful"); + exception_handling::assert(USER_CODE_SEGMENT_SELECTOR == current_segment, + "[Context Switching] Context switch into user mode not successful"); + exception_handling::assert(USER_DATA_SEGMENT_SELECTOR == kernel::cpu::validate_data_segment_registers(), + "[Context Switching] Context switch into user mode not successful"); - video::vga::text::write("User Mode!!!", video::vga::text::common_attributes::green_on_black); + video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } auto switch_to_user_mode() -> void diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index 9fb7433..cb367b6 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -1,6 +1,7 @@ #include "arch/kernel/cpu/segment_register.hpp" #include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" +#include "arch/exception_handling/assert.hpp" namespace teachos::arch::kernel::cpu { @@ -37,6 +38,26 @@ namespace teachos::arch::kernel::cpu return current_value; } - auto validate_segment_registers() -> context_switching::interrupt_descriptor_table::segment_selector {} + auto validate_data_segment_registers() -> context_switching::interrupt_descriptor_table::segment_selector + { + context_switching::interrupt_descriptor_table::segment_selector ss; + context_switching::interrupt_descriptor_table::segment_selector ds; + context_switching::interrupt_descriptor_table::segment_selector es; + context_switching::interrupt_descriptor_table::segment_selector fs; + context_switching::interrupt_descriptor_table::segment_selector gs; + + asm volatile( + "mov %%ss, %[ss_output]\n" + "mov %%ds, %[ds_output]\n" + "mov %%es, %[es_output]\n" + "mov %%fs, %[fs_output]\n" + "mov %%gs, %[gs_output]\n" + : [ss_output] "=r"(ss), [ds_output] "=r"(ds), [es_output] "=r"(es), [fs_output] "=r"(fs), [gs_output] "=r"(gs)); + + auto result = ss == ds && ss == es && ss == fs && ss == gs; + exception_handling::assert(result, "[Segment Register] Values in data register are not the same."); + + return ss; + } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 9a185c1533bd2197d0e830369b4cc26abf88e2c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 11 Apr 2025 09:25:04 +0000 Subject: Document methods and move them into kernel cpu folder --- arch/x86_64/src/context_switching/main.cpp | 63 ++++++------------------- arch/x86_64/src/kernel/cpu/segment_register.cpp | 48 +++++++++++++++++-- arch/x86_64/src/kernel/main.cpp | 6 +-- 3 files changed, 58 insertions(+), 59 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 0f2ec93..5cac878 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -12,46 +12,6 @@ namespace teachos::arch::context_switching { namespace { - - /** - * @brief Switch context into the mode defined in the segment selectors. - * - * Setup the stack IRETQ expects to switch the mode: - * 1. push data selector - * 2. push current stack pointer - * 3. push eflags - * 4. push code segment selector - * 5. push return address - * - * @param data_segment - * @param code_segment - * @param address - */ - [[gnu::naked]] - auto far_return(context_switching::interrupt_descriptor_table::segment_selector data_segment, - context_switching::interrupt_descriptor_table::segment_selector code_segment, uint64_t address) - -> void - { - asm volatile("mov %[data_segment], %%rax\n" - "mov %%rax, %%ds\n" - "mov %%rax, %%es\n" - "mov %%rax, %%fs\n" - "mov %%rax, %%gs\n" - "mov %%rsp, %%rax\n" - - "push %[data_segment]\n" - "push %%rax\n" - "pushfq\n" - "push %[code_segment]\n" - "mov %[return_function], %%rax\n" - "push %%rax\n" - - "iretq\n" - : - : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) - : "rax"); - } - constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ @@ -61,6 +21,14 @@ namespace teachos::arch::context_switching auto initialize_descriptor_tables() -> descriptor_tables { + static bool initalized = false; + if (initalized) + { + descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), + interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; + return tables; + } + kernel::cpu::clear_interrupt_flag(); segment_descriptor_table::update_global_descriptor_table_register(); @@ -68,7 +36,7 @@ namespace teachos::arch::context_switching interrupt_descriptor_table::segment_selector segment_selector{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{&kernel::cpu::reload_segment_registers, segment_selector}; + kernel::cpu::far_pointer pointer{&kernel::cpu::reload_data_segment_registers, segment_selector}; kernel::cpu::call(pointer); segment_descriptor_table::update_task_state_segment_register(); @@ -77,17 +45,13 @@ namespace teachos::arch::context_switching descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; + initalized = true; return tables; } auto user_mode_main() -> void { - auto current_segment = kernel::cpu::read_code_segment_register(); - exception_handling::assert(USER_CODE_SEGMENT_SELECTOR == current_segment, - "[Context Switching] Context switch into user mode not successful"); - exception_handling::assert(USER_DATA_SEGMENT_SELECTOR == kernel::cpu::validate_data_segment_registers(), - "[Context Switching] Context switch into user mode not successful"); - + kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } @@ -99,8 +63,9 @@ namespace teachos::arch::context_switching auto switch_context(interrupt_descriptor_table::segment_selector data_segment, interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void { - kernel::cpu::set_segment_registers(data_segment); - far_return(data_segment, code_segment, reinterpret_cast(return_function)); + (void)initialize_descriptor_tables(); + kernel::cpu::set_data_segment_registers(data_segment); + kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); } } // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index cb367b6..44b4eff 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -6,7 +6,7 @@ namespace teachos::arch::kernel::cpu { [[gnu::naked]] - auto reload_segment_registers() -> void + auto reload_data_segment_registers() -> void { asm volatile("xor %rax, %rax\n" "mov %rax, %ss\n" @@ -18,7 +18,8 @@ namespace teachos::arch::kernel::cpu } [[gnu::naked]] - auto set_segment_registers(context_switching::interrupt_descriptor_table::segment_selector segment_selector) -> void + auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector segment_selector) + -> void { asm volatile("xor %%rax, %%rax\n" "mov %[input], %%ax\n" @@ -38,7 +39,8 @@ namespace teachos::arch::kernel::cpu return current_value; } - auto validate_data_segment_registers() -> context_switching::interrupt_descriptor_table::segment_selector + auto validate_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) + -> void { context_switching::interrupt_descriptor_table::segment_selector ss; context_switching::interrupt_descriptor_table::segment_selector ds; @@ -54,10 +56,46 @@ namespace teachos::arch::kernel::cpu "mov %%gs, %[gs_output]\n" : [ss_output] "=r"(ss), [ds_output] "=r"(ds), [es_output] "=r"(es), [fs_output] "=r"(fs), [gs_output] "=r"(gs)); - auto result = ss == ds && ss == es && ss == fs && ss == gs; + auto result = (ss == ds && ss == es && ss == fs && ss == gs); exception_handling::assert(result, "[Segment Register] Values in data register are not the same."); + result = (ss == data_segment); + exception_handling::assert( + result, "[Segment Register] Expected Data Segment is not the same as the value in the Stack Segment register."); + } + + auto validate_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector code_segment) + -> void + { + auto const cs = read_code_segment_register(); + exception_handling::assert( + cs == code_segment, + "[Segment Register] Expected Code Segment is not the same as the value in the Code Segment register."); + } + + auto validate_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment, + context_switching::interrupt_descriptor_table::segment_selector code_segment) -> void + { + validate_data_segment_registers(data_segment); + validate_code_segment_register(code_segment); + } + + [[gnu::naked]] + auto set_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector data_segment, + context_switching::interrupt_descriptor_table::segment_selector code_segment, + uint64_t address) -> void + { + asm volatile("mov %%rsp, %%rax\n" + "push %[data_segment]\n" + "push %%rax\n" + "pushfq\n" + "push %[code_segment]\n" + "mov %[return_function], %%rax\n" + "push %%rax\n" - return ss; + "iretq\n" + : + : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) + : "rax"); } } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index b69064d..05c879e 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -61,11 +61,7 @@ namespace teachos::arch::kernel // stack_overflow_test(0); memory::heap::global_heap_allocator::register_heap_allocator(memory::heap::heap_allocator_type::LINKED_LIST); - - heap_test(); - - decltype(auto) descriptor_tables = context_switching::initialize_descriptor_tables(); - (void)descriptor_tables; + // heap_test(); context_switching::switch_to_user_mode(); } -- cgit v1.2.3 From 0c75a6ef8e47106e7fc51ca5e11eb4116e879e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 11 Apr 2025 10:50:03 +0000 Subject: Improve initialize_descriptor_tables --- arch/x86_64/src/context_switching/main.cpp | 31 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 5cac878..952a3b2 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -12,6 +12,10 @@ namespace teachos::arch::context_switching { namespace { + constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, + KERNEL_CODE_SEGMENT_SELECTOR}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ @@ -22,30 +26,23 @@ namespace teachos::arch::context_switching auto initialize_descriptor_tables() -> descriptor_tables { static bool initalized = false; - if (initalized) - { - descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), - interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; - return tables; - } - - kernel::cpu::clear_interrupt_flag(); - segment_descriptor_table::update_global_descriptor_table_register(); - interrupt_descriptor_table::update_interrupt_descriptor_table_register(); + if (!initalized) + { + kernel::cpu::clear_interrupt_flag(); - interrupt_descriptor_table::segment_selector segment_selector{ - 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - kernel::cpu::far_pointer pointer{&kernel::cpu::reload_data_segment_registers, segment_selector}; - kernel::cpu::call(pointer); + segment_descriptor_table::update_global_descriptor_table_register(); + interrupt_descriptor_table::update_interrupt_descriptor_table_register(); - segment_descriptor_table::update_task_state_segment_register(); + kernel::cpu::call(KERNEL_CODE_POINTER); + segment_descriptor_table::update_task_state_segment_register(); - kernel::cpu::set_interrupt_flag(); + kernel::cpu::set_interrupt_flag(); + initalized = true; + } descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; - initalized = true; return tables; } -- cgit v1.2.3 From 3c7250a32033700944ed6f3d2174756245b22e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 11 Apr 2025 13:37:55 +0000 Subject: Adjust variable name --- arch/x86_64/src/kernel/cpu/segment_register.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index 44b4eff..891d72c 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -18,8 +18,7 @@ namespace teachos::arch::kernel::cpu } [[gnu::naked]] - auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector segment_selector) - -> void + auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) -> void { asm volatile("xor %%rax, %%rax\n" "mov %[input], %%ax\n" @@ -29,7 +28,7 @@ namespace teachos::arch::kernel::cpu "mov %%rax, %%gs\n" "ret" : /* No output from call */ - : [input] "m"(segment_selector)); + : [input] "m"(data_segment)); } auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector -- cgit v1.2.3 From e5c62b114da77d278afe077b222b2f4feae2b94e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 11 Apr 2025 14:01:44 +0000 Subject: Add rax clobbered register to all segment register write calls --- arch/x86_64/src/kernel/cpu/segment_register.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index 891d72c..9933e92 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -14,7 +14,10 @@ namespace teachos::arch::kernel::cpu "mov %rax, %es\n" "mov %rax, %fs\n" "mov %rax, %gs\n" - "ret"); + "ret" + : /* No output from call */ + : /* No input to call */ + : "rax"); } [[gnu::naked]] @@ -28,7 +31,8 @@ namespace teachos::arch::kernel::cpu "mov %%rax, %%gs\n" "ret" : /* No output from call */ - : [input] "m"(data_segment)); + : [input] "m"(data_segment) + : "rax"); } auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector @@ -90,7 +94,6 @@ namespace teachos::arch::kernel::cpu "push %[code_segment]\n" "mov %[return_function], %%rax\n" "push %%rax\n" - "iretq\n" : : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) -- cgit v1.2.3 From 4909c80b31f3198030d3e666db87cfd39ac87c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 11 Apr 2025 14:07:29 +0000 Subject: Remove gnu::naked functions where not necessary. --- arch/x86_64/src/kernel/cpu/segment_register.cpp | 36 +++++++++++-------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index 9933e92..b59cd1b 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -5,22 +5,19 @@ namespace teachos::arch::kernel::cpu { - [[gnu::naked]] auto reload_data_segment_registers() -> void { - asm volatile("xor %rax, %rax\n" - "mov %rax, %ss\n" - "mov %rax, %ds\n" - "mov %rax, %es\n" - "mov %rax, %fs\n" - "mov %rax, %gs\n" - "ret" - : /* No output from call */ - : /* No input to call */ + asm volatile("xor %%rax, %%rax\n" + "mov %%rax, %%ss\n" + "mov %%rax, %%ds\n" + "mov %%rax, %%es\n" + "mov %%rax, %%fs\n" + "mov %%rax, %%gs\n" + : /* no output from call */ + : /* no input to call */ : "rax"); } - [[gnu::naked]] auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) -> void { asm volatile("xor %%rax, %%rax\n" @@ -29,15 +26,14 @@ namespace teachos::arch::kernel::cpu "mov %%rax, %%es\n" "mov %%rax, %%fs\n" "mov %%rax, %%gs\n" - "ret" - : /* No output from call */ + : /* no output from call */ : [input] "m"(data_segment) : "rax"); } auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector { - context_switching::interrupt_descriptor_table::segment_selector current_value; + context_switching::interrupt_descriptor_table::segment_selector current_value{}; asm volatile("mov %%cs, %[output]" : [output] "=r"(current_value)); return current_value; } @@ -45,11 +41,11 @@ namespace teachos::arch::kernel::cpu auto validate_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) -> void { - context_switching::interrupt_descriptor_table::segment_selector ss; - context_switching::interrupt_descriptor_table::segment_selector ds; - context_switching::interrupt_descriptor_table::segment_selector es; - context_switching::interrupt_descriptor_table::segment_selector fs; - context_switching::interrupt_descriptor_table::segment_selector gs; + context_switching::interrupt_descriptor_table::segment_selector ss{}; + context_switching::interrupt_descriptor_table::segment_selector ds{}; + context_switching::interrupt_descriptor_table::segment_selector es{}; + context_switching::interrupt_descriptor_table::segment_selector fs{}; + context_switching::interrupt_descriptor_table::segment_selector gs{}; asm volatile( "mov %%ss, %[ss_output]\n" @@ -95,7 +91,7 @@ namespace teachos::arch::kernel::cpu "mov %[return_function], %%rax\n" "push %%rax\n" "iretq\n" - : + : /* no output from call */ : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) : "rax"); } -- cgit v1.2.3 From eafe8533bb5ccbe15bd8ffbc917b38122b04a157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 14 Apr 2025 15:21:52 +0000 Subject: Add stack frame allocator. Fix stl vector bug and create stl stack implementation --- arch/x86_64/src/context_switching/main.cpp | 4 +- .../src/memory/allocator/area_frame_allocator.cpp | 2 +- .../src/memory/allocator/stack_frame_allocator.cpp | 105 +++++++++++++++++++++ arch/x86_64/src/memory/main.cpp | 20 +++- 4 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 952a3b2..486a09f 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -21,6 +21,8 @@ namespace teachos::arch::context_switching constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; + auto reload_global_descriptor_table_register() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } + } // namespace auto initialize_descriptor_tables() -> descriptor_tables @@ -34,7 +36,7 @@ namespace teachos::arch::context_switching segment_descriptor_table::update_global_descriptor_table_register(); interrupt_descriptor_table::update_interrupt_descriptor_table_register(); - kernel::cpu::call(KERNEL_CODE_POINTER); + reload_global_descriptor_table_register(); segment_descriptor_table::update_task_state_segment_register(); kernel::cpu::set_interrupt_flag(); diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index cb4fefa..a5a1b49 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -9,7 +9,7 @@ namespace teachos::arch::memory::allocator { area_frame_allocator::area_frame_allocator(multiboot::memory_information const & mem_info) - : next_free_frame(0U) + : next_free_frame() , current_area(std::nullopt) , memory_areas(mem_info.areas) , kernel_start(physical_frame::containing_address(mem_info.kernel_start)) diff --git a/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp new file mode 100644 index 0000000..0fa277a --- /dev/null +++ b/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp @@ -0,0 +1,105 @@ +#include "arch/memory/allocator/stack_frame_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" + +#include +#include +#include + +namespace teachos::arch::memory::allocator +{ + stack_frame_allocator::stack_frame_allocator(multiboot::memory_information const & mem_info) + : free_frames() + , next_free_frame() + , current_area(std::nullopt) + , memory_areas(mem_info.areas) + , kernel_start(physical_frame::containing_address(mem_info.kernel_start)) + , kernel_end(physical_frame::containing_address(mem_info.kernel_end)) + , multiboot_start(physical_frame::containing_address(mem_info.multiboot_start)) + , multiboot_end(physical_frame::containing_address(mem_info.multiboot_end)) + { + load_free_physical_frames(); + } + + auto stack_frame_allocator::load_free_physical_frames() -> void + { + choose_next_area(); + if (!current_area.has_value()) + { + return; + } + + auto const address = current_area.value().base_address + current_area.value().area_length - 1; + physical_frame const current_area_last_frame = physical_frame::containing_address(address); + + // Only try to allocate memory if current_area is not null, because + // the current_area is null if there is no more available memory. + while (next_free_frame <= current_area_last_frame) + { + if (next_free_frame >= kernel_start && next_free_frame <= kernel_end) + { + // `physical_frame` is used by the kernel or multiboot information structure. + next_free_frame = allocator::physical_frame{kernel_end.frame_number + 1}; + } + else if (next_free_frame >= multiboot_start && next_free_frame <= multiboot_end) + { + // `physical_frame` is used by the kernel or multiboot information structure. + next_free_frame = allocator::physical_frame{multiboot_end.frame_number + 1}; + } + else + { + // Frame is unused, increment `next_free_frame` and return it. + next_free_frame.frame_number += 1; + // TODO: Fix using heap like structure to initalize paging allocator used by heap does not work + // free_frames.push(next_free_frame); + static uint32_t count = 0U; + count++; + } + } + } + + auto stack_frame_allocator::choose_next_area() -> void + { + current_area = std::nullopt; + auto next_area_with_free_frames = memory_areas | std::views::filter([this](auto const & area) { + auto address = area.base_address + area.area_length - 1; + return physical_frame::containing_address(address) >= next_free_frame; + }); + + auto const lowest_area_with_free_frames = std::ranges::min_element( + next_area_with_free_frames, [](auto const & a, auto const & b) { return a.base_address < b.base_address; }); + + if (lowest_area_with_free_frames != next_area_with_free_frames.end()) + { + current_area = *lowest_area_with_free_frames; + // Update the `next_free_frame` according to the new memory area + auto const start_frame = physical_frame::containing_address(current_area.value().base_address); + if (next_free_frame < start_frame) + { + next_free_frame = start_frame; + } + } + } + + auto stack_frame_allocator::allocate_frame() -> std::optional + { + // If the underlying stack is empty that are no free frames left to allocate. + if (free_frames.empty()) + { + load_free_physical_frames(); + if (free_frames.empty()) + { + return std::nullopt; + } + } + + decltype(auto) top = free_frames.top(); + free_frames.pop(); + return top; + } + + auto stack_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void + { + free_frames.push(physical_frame); + } +} // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index a920a20..3041a75 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -4,6 +4,8 @@ #include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/msr.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" +#include "arch/memory/allocator/concept.hpp" +#include "arch/memory/allocator/stack_frame_allocator.hpp" #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" @@ -12,7 +14,21 @@ namespace teachos::arch::memory { namespace { - auto remap_heap(allocator::area_frame_allocator allocator, paging::active_page_table & active_table) -> void + template + auto create_frame_allocator(multiboot::memory_information const & memory_information) -> T + { + return allocator::area_frame_allocator{memory_information}; + } + + template<> + auto create_frame_allocator(multiboot::memory_information const & memory_information) + -> allocator::stack_frame_allocator + { + return allocator::stack_frame_allocator{memory_information}; + } + + template + auto remap_heap(T & allocator, paging::active_page_table & active_table) -> void { auto const start_page = paging::virtual_page::containing_address(memory::heap::HEAP_START); auto const end_page = @@ -36,7 +52,7 @@ namespace teachos::arch::memory has_been_called = true; auto const memory_information = multiboot::read_multiboot2(); - allocator::area_frame_allocator allocator(memory_information); + auto allocator = create_frame_allocator(memory_information); kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); -- cgit v1.2.3 From 576a7a95b2462ec4938de9fe344657ca04b2ba34 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 17 Apr 2025 14:14:49 +0000 Subject: add syscall interrupt handler --- .../interrupt_descriptor_table/interrupt_descriptor_table.cpp | 7 ++++++- arch/x86_64/src/context_switching/main.cpp | 3 +++ arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp | 7 +++++++ 3 files changed, 16 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index 80f01a8..c50ac1d 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -10,7 +10,7 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table { /// @brief Amount of currently reserved interrupt indicies. /// See https://wiki.osdev.org/Interrupt_Descriptor_Table#IDT_items for more information. - constexpr uint8_t RESERVED_INTERRUPT_COUNT = 32U; + constexpr uint16_t RESERVED_INTERRUPT_COUNT = 256U; auto create_interrupt_descriptor_table() -> interrupt_descriptor_table { @@ -26,6 +26,11 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table interrupt_descriptor_table.at(i) = {selector, ist, flags, offset}; } + interrupt_descriptor_table.at(0x80) = { + segment_selector{3U, segment_selector::REQUEST_LEVEL_USER}, ist_offset{0U}, + idt_flags{idt_flags::DESCRIPTOR_LEVEL_USER | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}, + uint64_t{reinterpret_cast(interrupt_handling::syscall_interrupt_handler)}}; + return interrupt_descriptor_table; } } // namespace diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 952a3b2..fc8790f 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -49,6 +49,9 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); + + asm volatile("INT $0x80"); + video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp index 4392b04..6075770 100644 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -11,4 +11,11 @@ namespace teachos::arch::interrupt_handling (void)frame; video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); } + + [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] + auto syscall_interrupt_handler(interrupt_frame * frame) -> void + { + (void)frame; + video::vga::text::write("A SYSCALL interrupt occurred.", video::vga::text::common_attributes::green_on_black); + } } // namespace teachos::arch::interrupt_handling -- cgit v1.2.3 From 5dc0e92a7211b44429c1a2e7efe19c146f5c4f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 19 Apr 2025 10:52:30 +0000 Subject: Remove deque --- arch/x86_64/src/memory/main.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 3041a75..bd094e0 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -5,7 +5,6 @@ #include "arch/kernel/cpu/msr.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/allocator/concept.hpp" -#include "arch/memory/allocator/stack_frame_allocator.hpp" #include "arch/memory/heap/heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" @@ -20,13 +19,6 @@ namespace teachos::arch::memory return allocator::area_frame_allocator{memory_information}; } - template<> - auto create_frame_allocator(multiboot::memory_information const & memory_information) - -> allocator::stack_frame_allocator - { - return allocator::stack_frame_allocator{memory_information}; - } - template auto remap_heap(T & allocator, paging::active_page_table & active_table) -> void { @@ -52,7 +44,7 @@ namespace teachos::arch::memory has_been_called = true; auto const memory_information = multiboot::read_multiboot2(); - auto allocator = create_frame_allocator(memory_information); + auto allocator = create_frame_allocator(memory_information); kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); -- cgit v1.2.3 From 0986058bb9ca5b4afd7c578c815dc3a4c08808a9 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Mon, 21 Apr 2025 08:18:41 +0000 Subject: WIP syscall --- .../interrupt_descriptor_table.cpp | 4 ++-- arch/x86_64/src/context_switching/main.cpp | 9 ++++++++- .../generic_interrupt_handler.cpp | 22 +++++++++++++++++++++- 3 files changed, 31 insertions(+), 4 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index c50ac1d..c041198 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -27,8 +27,8 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table } interrupt_descriptor_table.at(0x80) = { - segment_selector{3U, segment_selector::REQUEST_LEVEL_USER}, ist_offset{0U}, - idt_flags{idt_flags::DESCRIPTOR_LEVEL_USER | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}, + segment_selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}, ist_offset{0U}, + idt_flags{idt_flags::DESCRIPTOR_LEVEL_USER | idt_flags::TRAP_GATE | idt_flags::PRESENT}, uint64_t{reinterpret_cast(interrupt_handling::syscall_interrupt_handler)}}; return interrupt_descriptor_table; diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 7be286a..faaf831 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -52,7 +52,14 @@ namespace teachos::arch::context_switching { kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - asm volatile("INT $0x80"); + // TODO/INFO: + // https://stackoverflow.com/questions/46022184/osdev-syscall-sysret-and-sysenter-sysexit-instructions-enabling + // https://stackoverflow.com/questions/12806584/what-is-better-int-0x80-or-syscall-in-32-bit-code-on-linux + // + // People claim that SYSENTER is for 32-Bit, while SYSCALL is for 64-Bit! + + // asm volatile("INT $0x80"); + asm volatile("SYSCALL"); video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp index 6075770..7afd87d 100644 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -15,7 +15,27 @@ namespace teachos::arch::interrupt_handling [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] auto syscall_interrupt_handler(interrupt_frame * frame) -> void { + // RDI, RSI, RDX, RCX, R8, R9 + // RDI -> SYSCALL number + // Others are arguments + + // TODO: The registers are not available here. We need to set them up on the stack + // and access them via argument. + + uint64_t syscall_number{}; + asm volatile("mov %%rdi, %0" : "=r"(syscall_number)); + + // Handle system call based on the number + switch (syscall_number) + { + case 1: + video::vga::text::write("SYSCALL 1.", video::vga::text::common_attributes::green_on_black); + break; + default: + // Handle unknown syscall + break; + } + (void)frame; - video::vga::text::write("A SYSCALL interrupt occurred.", video::vga::text::common_attributes::green_on_black); } } // namespace teachos::arch::interrupt_handling -- cgit v1.2.3 From 5f149faeb9d41bb56733075b0e56908b3731d38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Apr 2025 09:32:59 +0000 Subject: Move gnu function attributes to header file --- arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp | 3 --- arch/x86_64/src/memory/heap/bump_allocator.cpp | 4 +++- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp index 7afd87d..60fb50c 100644 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -4,15 +4,12 @@ namespace teachos::arch::interrupt_handling { - - [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] auto generic_interrupt_handler(interrupt_frame * frame) -> void { (void)frame; video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); } - [[gnu::interrupt]] [[gnu::section(".interrupt_text")]] auto syscall_interrupt_handler(interrupt_frame * frame) -> void { // RDI, RSI, RDX, RCX, R8, R9 diff --git a/arch/x86_64/src/memory/heap/bump_allocator.cpp b/arch/x86_64/src/memory/heap/bump_allocator.cpp index df95346..525f45c 100644 --- a/arch/x86_64/src/memory/heap/bump_allocator.cpp +++ b/arch/x86_64/src/memory/heap/bump_allocator.cpp @@ -24,11 +24,13 @@ namespace teachos::arch::memory::heap auto bump_allocator::allocate(std::size_t size) -> void * { + // Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the + // exchange failed, becuase the value was not the expected one. + auto alloc_start = next.load(std::memory_order::relaxed); // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time // causing the value to differ and the calculation to have to be redone. for (;;) { - auto alloc_start = next.load(std::memory_order::relaxed); auto const alloc_end = saturating_add(alloc_start, size); arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory"); // Check if the atomic value is still the one initally loaded, if it isn't we have been overtaken by another -- cgit v1.2.3 From c865eff02ae1978b4f665432d853374d1ffacecf Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 10:21:29 +0000 Subject: create trampoline for syscall --- arch/x86_64/src/boot/boot.s | 25 +++++++++++++++++++++++++ arch/x86_64/src/context_switching/main.cpp | 4 +++- 2 files changed, 28 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 7932045..24b38ca 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -352,6 +352,31 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 +syscall_target: + iretq + +.global syscall_trampoline +syscall_trampoline: + /* Write target function pointer in IA32_LSTAR MSR */ + mov $0xC0000082, %ecx /* IA32_LSTAR MSR */ + lea [syscall_target], %rax + lea [syscall_target], %rdx + shr $32, %rdx + wrmsr + + /* Write ... in IA32_LSTAR MSR */ + mov $0xC0000084, %ecx /* IA32_FMASK MSR */ + mov $0x0, %rax /* ... lower 32 bits */ + mov $0x0, %rdx /* ... upper 32 bits */ + wrmsr + + /* Write Segment selector in IA32_STAR MSR */ + mov $0xC0000081, %ecx /* IA32_STAR MSR */ + mov $0x10, %rax /* SS lower 32 bits */ + mov $0x0, %rdx /* SS upper 32 bits */ + wrmsr + + _transition_to_long_mode: xor %rax, %rax mov %rax, %ss diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index faaf831..c949488 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,5 +1,6 @@ #include "arch/context_switching/main.hpp" +#include "arch/boot/pointers.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" @@ -59,7 +60,8 @@ namespace teachos::arch::context_switching // People claim that SYSENTER is for 32-Bit, while SYSCALL is for 64-Bit! // asm volatile("INT $0x80"); - asm volatile("SYSCALL"); + // asm volatile("SYSCALL"); + boot::syscall_trampoline(); video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } -- cgit v1.2.3 From 7261c64bb236a313ed8846a9c9dbded6890a9e98 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 11:20:02 +0000 Subject: wip implement syscall in cpp --- arch/x86_64/src/boot/boot.s | 25 ------------- arch/x86_64/src/context_switching/main.cpp | 43 +++++++++++++++++----- .../src/context_switching/syscall_handler.cpp | 20 ++++++++++ arch/x86_64/src/kernel/main.cpp | 1 + 4 files changed, 55 insertions(+), 34 deletions(-) create mode 100644 arch/x86_64/src/context_switching/syscall_handler.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 24b38ca..7932045 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -352,31 +352,6 @@ prepare_page_maps: .section .boot_text, "ax", @progbits .code64 -syscall_target: - iretq - -.global syscall_trampoline -syscall_trampoline: - /* Write target function pointer in IA32_LSTAR MSR */ - mov $0xC0000082, %ecx /* IA32_LSTAR MSR */ - lea [syscall_target], %rax - lea [syscall_target], %rdx - shr $32, %rdx - wrmsr - - /* Write ... in IA32_LSTAR MSR */ - mov $0xC0000084, %ecx /* IA32_FMASK MSR */ - mov $0x0, %rax /* ... lower 32 bits */ - mov $0x0, %rdx /* ... upper 32 bits */ - wrmsr - - /* Write Segment selector in IA32_STAR MSR */ - mov $0xC0000081, %ecx /* IA32_STAR MSR */ - mov $0x10, %rax /* SS lower 32 bits */ - mov $0x0, %rdx /* SS upper 32 bits */ - wrmsr - - _transition_to_long_mode: xor %rax, %rax mov %rax, %ss diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index c949488..85cefe5 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,6 +1,7 @@ #include "arch/context_switching/main.hpp" #include "arch/boot/pointers.hpp" +#include "arch/context_switching/syscall_handler.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" @@ -53,15 +54,7 @@ namespace teachos::arch::context_switching { kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - // TODO/INFO: - // https://stackoverflow.com/questions/46022184/osdev-syscall-sysret-and-sysenter-sysexit-instructions-enabling - // https://stackoverflow.com/questions/12806584/what-is-better-int-0x80-or-syscall-in-32-bit-code-on-linux - // - // People claim that SYSENTER is for 32-Bit, while SYSCALL is for 64-Bit! - - // asm volatile("INT $0x80"); - // asm volatile("SYSCALL"); - boot::syscall_trampoline(); + asm volatile("SYSCALL"); video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); } @@ -79,4 +72,36 @@ namespace teachos::arch::context_switching kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); } + auto setup_syscall() -> void + { + uint64_t handler = reinterpret_cast(syscall_handler); + asm volatile( + /* Write syscall_handler pointer in IA32_LSTAR MSR */ + "mov $0xC0000082, %%ecx\n" /* IA32_LSTAR MSR */ + "mov %[syscall_handler], %%rax" + "mov %[syscall_handler], %%rdx" + "shr $32, %%rdx\n" + "wrmsr\n" + + /* Write RFLAGS Mask in IA32_LSTAR MSR */ + "mov $0xC0000084, %%ecx\n" /* IA32_FMASK MSR */ + "mov $0x0, %%rax\n" /* RFLAGS Mask lower 32 bits */ + "mov $0x0, %%rdx\n" /* RFLAGS Mask upper 32 bits */ + "wrmsr\n" + + /* Write kernel code segment offset in IA32_STAR MSR */ + "mov $0xC0000081, %%ecx\n" /* IA32_STAR MSR */ + "mov $0x10, %%rax\n" /* kernel code segment offset lower 32 bits */ + "mov $0x0, %%rdx\n" /* kernel code segment offset upper 32 bits */ + "wrmsr\n" + + /* Set SCE bit in MSR_EFER (enabling syscall instruction)*/ + "mov $0xC0000080, %%ecx\n" + "rdmsr\n" + "or $0x1, %%eax\n" + "wrmsr" + : /* no output from call */ + : [syscall_handler] "r"(handler)); + } + } // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/context_switching/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall_handler.cpp new file mode 100644 index 0000000..1bc4ef9 --- /dev/null +++ b/arch/x86_64/src/context_switching/syscall_handler.cpp @@ -0,0 +1,20 @@ +#include "arch/context_switching/syscall_handler.hpp" + +#include + +namespace teachos::arch::context_switching +{ + [[gnu::naked]] + auto syscall_handler() -> void + { + uint64_t dummy{}; + switch (dummy) + { + case 0: + break; + default: + break; + } + asm volatile("SYSRET"); + } +} // namespace teachos::arch::context_switching \ No newline at end of file diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 05c879e..e737d44 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -63,6 +63,7 @@ namespace teachos::arch::kernel memory::heap::global_heap_allocator::register_heap_allocator(memory::heap::heap_allocator_type::LINKED_LIST); // heap_test(); + context_switching::setup_syscall(); context_switching::switch_to_user_mode(); } } // namespace teachos::arch::kernel -- cgit v1.2.3 From 187eba4eca3ea46d8c26419168e525242338dae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Apr 2025 13:18:49 +0000 Subject: Simplify syscall setup --- arch/x86_64/src/context_switching/main.cpp | 40 +++++++--------------- .../src/context_switching/syscall_handler.cpp | 1 - arch/x86_64/src/kernel/cpu/segment_register.cpp | 1 - 3 files changed, 12 insertions(+), 30 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 85cefe5..155d150 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -6,6 +6,7 @@ #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/if.hpp" +#include "arch/kernel/cpu/msr.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" #include "arch/video/vga/text.hpp" @@ -14,6 +15,10 @@ namespace teachos::arch::context_switching { namespace { + auto constexpr IA32_STAR_ADDRESS = 0xC0000081; + auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; + auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; + constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, @@ -74,34 +79,13 @@ namespace teachos::arch::context_switching auto setup_syscall() -> void { - uint64_t handler = reinterpret_cast(syscall_handler); - asm volatile( - /* Write syscall_handler pointer in IA32_LSTAR MSR */ - "mov $0xC0000082, %%ecx\n" /* IA32_LSTAR MSR */ - "mov %[syscall_handler], %%rax" - "mov %[syscall_handler], %%rdx" - "shr $32, %%rdx\n" - "wrmsr\n" - - /* Write RFLAGS Mask in IA32_LSTAR MSR */ - "mov $0xC0000084, %%ecx\n" /* IA32_FMASK MSR */ - "mov $0x0, %%rax\n" /* RFLAGS Mask lower 32 bits */ - "mov $0x0, %%rdx\n" /* RFLAGS Mask upper 32 bits */ - "wrmsr\n" - - /* Write kernel code segment offset in IA32_STAR MSR */ - "mov $0xC0000081, %%ecx\n" /* IA32_STAR MSR */ - "mov $0x10, %%rax\n" /* kernel code segment offset lower 32 bits */ - "mov $0x0, %%rdx\n" /* kernel code segment offset upper 32 bits */ - "wrmsr\n" - - /* Set SCE bit in MSR_EFER (enabling syscall instruction)*/ - "mov $0xC0000080, %%ecx\n" - "rdmsr\n" - "or $0x1, %%eax\n" - "wrmsr" - : /* no output from call */ - : [syscall_handler] "r"(handler)); + uint64_t const syscall_function = reinterpret_cast(syscall_handler); + uint64_t const segment_selector = *reinterpret_cast(&KERNEL_CODE_SEGMENT_SELECTOR); + + kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); + kernel::cpu::write_msr(IA32_STAR_ADDRESS, segment_selector); + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); } } // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/context_switching/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall_handler.cpp index 1bc4ef9..283d297 100644 --- a/arch/x86_64/src/context_switching/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall_handler.cpp @@ -4,7 +4,6 @@ namespace teachos::arch::context_switching { - [[gnu::naked]] auto syscall_handler() -> void { uint64_t dummy{}; diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp index b59cd1b..b08c9c4 100644 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ b/arch/x86_64/src/kernel/cpu/segment_register.cpp @@ -78,7 +78,6 @@ namespace teachos::arch::kernel::cpu validate_code_segment_register(code_segment); } - [[gnu::naked]] auto set_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector data_segment, context_switching::interrupt_descriptor_table::segment_selector code_segment, uint64_t address) -> void -- cgit v1.2.3 From 13dd2bd5a88ec7efeadf8586778f2c5a26d8cd9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Apr 2025 14:07:33 +0000 Subject: Move not public methods into anonymous namespace --- arch/x86_64/src/context_switching/main.cpp | 59 ++++++++++++++-------- .../src/context_switching/syscall_handler.cpp | 19 ------- arch/x86_64/src/kernel/cpu/msr.cpp | 2 +- arch/x86_64/src/kernel/main.cpp | 1 - 4 files changed, 39 insertions(+), 42 deletions(-) delete mode 100644 arch/x86_64/src/context_switching/syscall_handler.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 155d150..f73cb19 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,7 +1,6 @@ #include "arch/context_switching/main.hpp" #include "arch/boot/pointers.hpp" -#include "arch/context_switching/syscall_handler.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" @@ -30,6 +29,43 @@ namespace teachos::arch::context_switching auto reload_global_descriptor_table_register() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } + auto user_mode_main() -> void + { + kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); + + video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); + + asm volatile("syscall"); + + kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); + + video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRET!", + video::vga::text::common_attributes::green_on_black); + } + + auto syscall_handler() -> void + { + uint64_t dummy{}; + switch (dummy) + { + case 0: + break; + default: + break; + } + + asm volatile("sysretq"); + } + + auto enable_systemcall() -> void + { + uint64_t const syscall_function = reinterpret_cast(syscall_handler); + kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); + kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); + } + } // namespace auto initialize_descriptor_tables() -> descriptor_tables @@ -55,17 +91,9 @@ namespace teachos::arch::context_switching return tables; } - auto user_mode_main() -> void - { - kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - - asm volatile("SYSCALL"); - - video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); - } - auto switch_to_user_mode() -> void { + enable_systemcall(); switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user_mode_main); } @@ -77,15 +105,4 @@ namespace teachos::arch::context_switching kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); } - auto setup_syscall() -> void - { - uint64_t const syscall_function = reinterpret_cast(syscall_handler); - uint64_t const segment_selector = *reinterpret_cast(&KERNEL_CODE_SEGMENT_SELECTOR); - - kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - kernel::cpu::write_msr(IA32_STAR_ADDRESS, segment_selector); - kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); - } - } // namespace teachos::arch::context_switching diff --git a/arch/x86_64/src/context_switching/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall_handler.cpp deleted file mode 100644 index 283d297..0000000 --- a/arch/x86_64/src/context_switching/syscall_handler.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "arch/context_switching/syscall_handler.hpp" - -#include - -namespace teachos::arch::context_switching -{ - auto syscall_handler() -> void - { - uint64_t dummy{}; - switch (dummy) - { - case 0: - break; - default: - break; - } - asm volatile("SYSRET"); - } -} // namespace teachos::arch::context_switching \ No newline at end of file diff --git a/arch/x86_64/src/kernel/cpu/msr.cpp b/arch/x86_64/src/kernel/cpu/msr.cpp index 6249f8f..9c474a1 100644 --- a/arch/x86_64/src/kernel/cpu/msr.cpp +++ b/arch/x86_64/src/kernel/cpu/msr.cpp @@ -16,7 +16,7 @@ namespace teachos::arch::kernel::cpu auto write_msr(uint32_t msr, uint64_t value) -> void { - uint32_t low = value & 0xFFFFFFFF; + uint32_t low = value; uint32_t high = value >> 32; asm volatile("wrmsr" : /* no output from call */ diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index e737d44..05c879e 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -63,7 +63,6 @@ namespace teachos::arch::kernel memory::heap::global_heap_allocator::register_heap_allocator(memory::heap::heap_allocator_type::LINKED_LIST); // heap_test(); - context_switching::setup_syscall(); context_switching::switch_to_user_mode(); } } // namespace teachos::arch::kernel -- cgit v1.2.3 From a8a8e09ed39268839ca838c44489bb1352892fef Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 14:11:43 +0000 Subject: merge --- arch/x86_64/src/context_switching/main.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index f73cb19..287ced4 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -104,5 +104,4 @@ namespace teachos::arch::context_switching kernel::cpu::set_data_segment_registers(data_segment); kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); } - } // namespace teachos::arch::context_switching -- cgit v1.2.3 From 7c5a40a0de0c5e3ce0a51aa5414c4a433190c60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Apr 2025 14:17:19 +0000 Subject: Add validate methods. For WIP systemcall --- arch/x86_64/src/context_switching/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 287ced4..bd48e18 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -20,6 +20,8 @@ namespace teachos::arch::context_switching constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + constexpr interrupt_descriptor_table::segment_selector KERNEL_DATA_SEGMENT_SELECTOR{ + 2U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, KERNEL_CODE_SEGMENT_SELECTOR}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ @@ -45,6 +47,8 @@ namespace teachos::arch::context_switching auto syscall_handler() -> void { + kernel::cpu::validate_segment_registers(KERNEL_CODE_SEGMENT_SELECTOR, KERNEL_DATA_SEGMENT_SELECTOR); + uint64_t dummy{}; switch (dummy) { -- cgit v1.2.3 From 95c299db969b29eb4a4742ff7715adecfe138bd5 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 14:43:31 +0000 Subject: test different values --- arch/x86_64/src/context_switching/main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 287ced4..4e13b1c 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -62,7 +62,16 @@ namespace teachos::arch::context_switching uint64_t const syscall_function = reinterpret_cast(syscall_handler); 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; // Your 64-bit kernel code segment selector + uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR + 0x3; // User mode code segment selector (RPL=3) + + uint64_t star_value = (user_cs << 48) | (kernel_cs << 32); + + kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); + + // kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); } -- cgit v1.2.3 From adb66c18b9e6ca0f65934f453afda1c5f9fe145f Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Apr 2025 15:14:04 +0000 Subject: wip enable syscall --- arch/x86_64/src/context_switching/main.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 33af765..21299da 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -33,22 +33,16 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { - kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); asm volatile("syscall"); - kernel::cpu::validate_segment_registers(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR); - - video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRET!", + video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRETQ!", video::vga::text::common_attributes::green_on_black); } auto syscall_handler() -> void { - kernel::cpu::validate_segment_registers(KERNEL_CODE_SEGMENT_SELECTOR, KERNEL_DATA_SEGMENT_SELECTOR); - uint64_t dummy{}; switch (dummy) { @@ -65,17 +59,19 @@ namespace teachos::arch::context_switching { uint64_t const syscall_function = reinterpret_cast(syscall_handler); 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; // Your 64-bit kernel code segment selector - uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR + 0x3; // User mode code segment selector (RPL=3) - - uint64_t star_value = (user_cs << 48) | (kernel_cs << 32); - + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 1 << 9U); // Disable interrupt flag during syscall + + // @MTO: This produces following values: + // After SYSCALL: CS = 0x10, SS = 0x18 + // After SYSRETQ: CS = 0x43, SS = 0x3b + // + // We probably need to modify our GDT, because the cs+8 = ss is an issue we cannot solve. + // Also, CS = 0x43 is weird. I expected it to be 0x33. + uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; + uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR; + uint64_t star_value = (kernel_cs << 32) | (user_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); - kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); - // kernel::cpu::write_msr(IA32_STAR_ADDRESS, KERNEL_CODE_SEGMENT_SELECTOR); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); } -- cgit v1.2.3 From ecdfbc3e1458923f619f0d4b8a841a6e96a6678a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 29 Apr 2025 15:01:44 +0000 Subject: Start adding parameters to syscall --- arch/x86_64/src/context_switching/main.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 21299da..2a2a188 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -35,6 +35,11 @@ namespace teachos::arch::context_switching { video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); + uint64_t new_value = 60U; + asm volatile("mov %[input], %%rax" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); asm volatile("syscall"); video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRETQ!", @@ -43,10 +48,16 @@ namespace teachos::arch::context_switching auto syscall_handler() -> void { - uint64_t dummy{}; - switch (dummy) + uint64_t syscall_number{}; + asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_number)); + + switch (syscall_number) { - case 0: + case 1: + // Write VGA + break; + case 60U: + // Exit break; default: break; -- cgit v1.2.3 From f0627d43909a8c19f41f3699757918c0185b5f1a Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Wed, 30 Apr 2025 12:53:44 +0000 Subject: fix cs register after sysretq --- arch/x86_64/src/context_switching/main.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 2a2a188..8d1c019 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -42,7 +42,7 @@ namespace teachos::arch::context_switching : "memory"); asm volatile("syscall"); - video::vga::text::write("Successfully made a SYSCALL and returned back with SYSRETQ!", + video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", video::vga::text::common_attributes::green_on_black); } @@ -70,16 +70,12 @@ namespace teachos::arch::context_switching { uint64_t const syscall_function = reinterpret_cast(syscall_handler); kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 1 << 9U); // Disable interrupt flag during syscall - - // @MTO: This produces following values: - // After SYSCALL: CS = 0x10, SS = 0x18 - // After SYSRETQ: CS = 0x43, SS = 0x3b - // - // We probably need to modify our GDT, because the cs+8 = ss is an issue we cannot solve. - // Also, CS = 0x43 is weird. I expected it to be 0x33. + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 1 << 9U); // Disable interrupt flag during syscall. + uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR; + // We want to provide the user code segment, but the instruction calculates + 0x10 to fill the + // cs register (See https://www.felixcloutier.com/x86/sysret). + uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR - 0x10; uint64_t star_value = (kernel_cs << 32) | (user_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); -- cgit v1.2.3 From 5eb8d63a6ece530cb1d56217a046553b4b96245d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 30 Apr 2025 14:50:34 +0000 Subject: Note linux calling contract for implementation --- arch/x86_64/src/context_switching/main.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 8d1c019..7db9583 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -35,6 +35,16 @@ namespace teachos::arch::context_switching { video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); + // RFLAGS is saved into R11, RIP of the next instruction into RCX + // Required for SYSRETURN to know where to return too. + // Additional state needs to be saved by calling convention: + + // Syscall Number: RAX, Return Value: RAX (0 indicating no error, and -1 indicating an error, use as a boolean) + // Argument in this order (max 6. no argument on stack): RDI, RSI, RDX, R10, R8, R9 + // Not used registers: RBX, RSP, R12, R13, R14 + + // 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; asm volatile("mov %[input], %%rax" : /* no output from call */ @@ -70,7 +80,7 @@ namespace teachos::arch::context_switching { uint64_t const syscall_function = reinterpret_cast(syscall_handler); kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 1 << 9U); // Disable interrupt flag during syscall. + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; // We want to provide the user code segment, but the instruction calculates + 0x10 to fill the -- cgit v1.2.3 From 7c045d8ded72017ff11fd4b9b02148987b944caf Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 1 May 2025 12:25:40 +0000 Subject: WIP experiment with converting GDT to 8-Byte entries --- arch/x86_64/src/context_switching/main.cpp | 24 +++++--- .../global_descriptor_table.cpp | 65 ++++++++++++---------- .../global_descriptor_table_pointer.cpp | 3 +- .../segment_descriptor.cpp | 11 ++++ .../segment_descriptor_base.cpp | 13 +++++ .../segment_descriptor_extension.cpp | 10 ++++ arch/x86_64/src/kernel/cpu/call.cpp | 3 +- 7 files changed, 90 insertions(+), 39 deletions(-) create mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp create mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 7db9583..5901998 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -29,7 +29,19 @@ namespace teachos::arch::context_switching constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - auto reload_global_descriptor_table_register() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } + 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"); + + kernel::cpu::call(KERNEL_CODE_POINTER); + } auto user_mode_main() -> void { @@ -83,9 +95,7 @@ namespace teachos::arch::context_switching kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); uint64_t kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - // We want to provide the user code segment, but the instruction calculates + 0x10 to fill the - // cs register (See https://www.felixcloutier.com/x86/sysret). - uint64_t user_cs = USER_CODE_SEGMENT_SELECTOR - 0x10; + uint64_t user_cs = KERNEL_CODE_SEGMENT_SELECTOR; uint64_t star_value = (kernel_cs << 32) | (user_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); @@ -102,17 +112,17 @@ namespace teachos::arch::context_switching { kernel::cpu::clear_interrupt_flag(); - segment_descriptor_table::update_global_descriptor_table_register(); + segment_descriptor_table::update_gdtr(); interrupt_descriptor_table::update_interrupt_descriptor_table_register(); - reload_global_descriptor_table_register(); + reload_gdtr(); segment_descriptor_table::update_task_state_segment_register(); kernel::cpu::set_interrupt_flag(); initalized = true; } - descriptor_tables tables = {segment_descriptor_table::get_or_create_global_descriptor_table(), + descriptor_tables tables = {segment_descriptor_table::get_or_create_gdt(), interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; return tables; } 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 a497632..dd22603 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,11 +1,11 @@ #include "arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp" -#include "arch/context_switching/segment_descriptor_table/segment_descriptor.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" -#include "arch/stl/vector.hpp" namespace teachos::arch::context_switching::segment_descriptor_table { @@ -26,7 +26,6 @@ namespace teachos::arch::context_switching::segment_descriptor_table } else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) { - flags |= gdt_flags::UPPER_BOUND; access_level |= access_byte::WRITABLE; } @@ -34,7 +33,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table return segment_descriptor; } - auto create_task_state_segment_descriptor(task_state_segment * tss) -> segment_descriptor + auto create_tss_descriptor(task_state_segment * tss) -> segment_descriptor { constexpr uint64_t TSS_LIMIT = sizeof(task_state_segment) - 1; access_byte const tss_access_byte{access_byte::PRESENT | access_byte::DESCRIPTOR_LEVEL_KERNEL | @@ -45,43 +44,51 @@ namespace teachos::arch::context_switching::segment_descriptor_table return tss_descriptor; } - auto create_global_descriptor_table() -> global_descriptor_table + auto create_gdt() -> global_descriptor_table * { - segment_descriptor const null_segment{0}; - segment_descriptor const kernel_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor const kernel_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor const user_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); - segment_descriptor const user_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); + 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)}; // Task State Segment needs to be kept alive static auto tss = new task_state_segment(); - segment_descriptor const tss_descriptor = create_task_state_segment_descriptor(tss); - - global_descriptor_table global_descriptor_table{null_segment, kernel_code_segment, kernel_data_segment, - user_code_segment, user_data_segment, tss_descriptor}; - return global_descriptor_table; - } + 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; + }; } // namespace - auto get_or_create_global_descriptor_table() -> global_descriptor_table & + auto get_or_create_gdt() -> global_descriptor_table & { // Global Descriptor Table needs to be kept alive - static global_descriptor_table gdt = create_global_descriptor_table(); - return gdt; + static global_descriptor_table * gdt = create_gdt(); + return *gdt; } - auto update_global_descriptor_table_register() -> void + auto update_gdtr() -> void { - decltype(auto) gdt = get_or_create_global_descriptor_table(); + decltype(auto) gdt = get_or_create_gdt(); // 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((gdt.size() * sizeof(segment_descriptor)) - 1), - gdt.data()}; + global_descriptor_table_pointer gdt_pointer{static_cast((7 * sizeof(seg_desc)) - 1), &gdt.null}; kernel::cpu::load_global_descriptor_table(gdt_pointer); auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); @@ -92,11 +99,11 @@ namespace teachos::arch::context_switching::segment_descriptor_table auto update_task_state_segment_register() -> void { - decltype(auto) gdt = get_or_create_global_descriptor_table(); + 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 = (gdt.size() - 1) * sizeof(segment_descriptor_table::segment_descriptor); + uint16_t const tss_selector = (7 - 1) * sizeof(segment_descriptor_table::segment_descriptor); 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 a4a5de8..b7d2da4 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,8 +2,7 @@ namespace teachos::arch::context_switching::segment_descriptor_table { - global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, - segment_descriptor * address) + global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, seg_desc * 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 index 74f93b2..e74156b 100644 --- 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 @@ -32,4 +32,15 @@ namespace teachos::arch::context_switching::segment_descriptor_table return _access.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT : segment_descriptor_type::DATA_SEGMENT; } + + auto segment_descriptor::get_limit_1() -> uint16_t { return _limit_1; } + + auto segment_descriptor::get_base_1() -> uint32_t { return _base_1; } + + auto segment_descriptor::get_access() -> access_byte { return _access; } + + auto segment_descriptor::get_flag() -> gdt_flags { return _flag; } + + auto segment_descriptor::get_base_2() -> uint64_t { return _base_2; } + } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp new file mode 100644 index 0000000..f82dbb9 --- /dev/null +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp @@ -0,0 +1,13 @@ +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + segment_descriptor_base::segment_descriptor_base(segment_descriptor segment_descriptor) + : _limit_1(segment_descriptor.get_limit_1()) + , _base_1(segment_descriptor.get_base_1()) + , _access(segment_descriptor.get_access()) + , _flag(segment_descriptor.get_flag()) + { + // Nothing to do + } +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp new file mode 100644 index 0000000..b2649d0 --- /dev/null +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp @@ -0,0 +1,10 @@ +#include "arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp" + +namespace teachos::arch::context_switching::segment_descriptor_table +{ + segment_descriptor_extension::segment_descriptor_extension(segment_descriptor segment_descriptor) + : _base_2(segment_descriptor.get_base_2()) + { + // Nothing to do + } +} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/call.cpp b/arch/x86_64/src/kernel/cpu/call.cpp index 98fa248..932d248 100644 --- a/arch/x86_64/src/kernel/cpu/call.cpp +++ b/arch/x86_64/src/kernel/cpu/call.cpp @@ -4,6 +4,7 @@ namespace teachos::arch::kernel::cpu { auto call(far_pointer pointer) -> void { - asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); + // asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); + asm volatile("ljmp *%0" : : "m"(pointer)); } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 099a7fbbc35a71f98553fa39899f2d17c555242f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 2 May 2025 14:49:06 +0000 Subject: Finish implementing 8-byte GDT entries and syscall arg loads. --- .../segment_selector.cpp | 2 + arch/x86_64/src/context_switching/main.cpp | 58 +++++++++++------ .../global_descriptor_table.cpp | 75 ++++++++++------------ .../global_descriptor_table_pointer.cpp | 2 +- .../segment_descriptor.cpp | 46 ------------- .../segment_descriptor_base.cpp | 35 ++++++++-- .../segment_descriptor_extension.cpp | 18 +++++- arch/x86_64/src/kernel/cpu/call.cpp | 4 +- arch/x86_64/src/kernel/cpu/tr.cpp | 8 +-- 9 files changed, 127 insertions(+), 121 deletions(-) delete mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor.cpp (limited to 'arch/x86_64/src') 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(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(tss), - TSS_LIMIT}; + segment_descriptor_extension const tss_descriptor{tss_access_byte, tss_gdt_flags, reinterpret_cast(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((7 * sizeof(seg_desc)) - 1), &gdt.null}; + uint16_t gdt_size = static_cast((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 - } - - 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.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT - : segment_descriptor_type::DATA_SEGMENT; - } - - auto segment_descriptor::get_limit_1() -> uint16_t { return _limit_1; } - - auto segment_descriptor::get_base_1() -> uint32_t { return _base_1; } - - auto segment_descriptor::get_access() -> access_byte { return _access; } - - auto segment_descriptor::get_flag() -> gdt_flags { return _flag; } - - auto segment_descriptor::get_base_2() -> uint64_t { return _base_2; } - -} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp index f82dbb9..04804d9 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp @@ -2,12 +2,37 @@ namespace teachos::arch::context_switching::segment_descriptor_table { - segment_descriptor_base::segment_descriptor_base(segment_descriptor segment_descriptor) - : _limit_1(segment_descriptor.get_limit_1()) - , _base_1(segment_descriptor.get_base_1()) - , _access(segment_descriptor.get_access()) - , _flag(segment_descriptor.get_flag()) + segment_descriptor_base::segment_descriptor_base(uint64_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_base::segment_descriptor_base(access_byte access_byte, gdt_flags flags, uint32_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 } + + auto segment_descriptor_base::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.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT + : segment_descriptor_type::DATA_SEGMENT; + } + + segment_descriptor_base::operator uint64_t() const { return *reinterpret_cast(this); } + } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp index b2649d0..a28ec9b 100644 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp +++ b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp @@ -2,9 +2,23 @@ namespace teachos::arch::context_switching::segment_descriptor_table { - segment_descriptor_extension::segment_descriptor_extension(segment_descriptor segment_descriptor) - : _base_2(segment_descriptor.get_base_2()) + segment_descriptor_extension::segment_descriptor_extension(uint128_t flags) + : _base(flags) + , _base_3(flags >> 64U) + { + // Nothing to do. + } + + segment_descriptor_extension::segment_descriptor_extension(access_byte access_byte, gdt_flags flags, uint64_t base, + std::bitset<20U> limit) + : _base(access_byte, flags, base, limit) + , _base_3(base >> 32U) { // Nothing to do } + + auto segment_descriptor_extension::get_first_gdt_entry() const -> segment_descriptor_base { return _base; } + + auto segment_descriptor_extension::get_second_gdt_entry() const -> uint64_t { return _base_3; } + } // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/kernel/cpu/call.cpp b/arch/x86_64/src/kernel/cpu/call.cpp index 932d248..6564b76 100644 --- a/arch/x86_64/src/kernel/cpu/call.cpp +++ b/arch/x86_64/src/kernel/cpu/call.cpp @@ -4,7 +4,7 @@ namespace teachos::arch::kernel::cpu { auto call(far_pointer pointer) -> void { - // asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); - asm volatile("ljmp *%0" : : "m"(pointer)); + asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); + // asm volatile("ljmp *%0" : : "m"(pointer)); } } // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/tr.cpp b/arch/x86_64/src/kernel/cpu/tr.cpp index e281189..a435540 100644 --- a/arch/x86_64/src/kernel/cpu/tr.cpp +++ b/arch/x86_64/src/kernel/cpu/tr.cpp @@ -11,12 +11,6 @@ namespace teachos::arch::kernel::cpu auto load_task_register(uint16_t gdt_offset) -> void { - // asm volatile("ltr %[input]" : /* no output from call */ : [input] "R"(gdt_offset)); - // https://www.scs.stanford.edu/05au-cs240c/lab/i386/s07_03.htm - asm volatile("mov %[input], %%ax\n" - "ltr %%ax\n" - : /* no output from call */ - : [input] "r"(gdt_offset) - : "ax"); + asm volatile("ltr %[input]" : /* no output from call */ : [input] "m"(gdt_offset)); } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 4b8674bee6089aef1e2c6b9064c6109f1cd392da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 3 May 2025 07:24:55 +0000 Subject: Remove zomby code and fix 32-bit compability crash --- arch/x86_64/src/context_switching/main.cpp | 38 +++++++----------------------- arch/x86_64/src/kernel/cpu/call.cpp | 1 - 2 files changed, 8 insertions(+), 31 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 7449d84..06c0810 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -20,8 +20,6 @@ namespace teachos::arch::context_switching constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - constexpr interrupt_descriptor_table::segment_selector KERNEL_DATA_SEGMENT_SELECTOR{ - 2U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, KERNEL_CODE_SEGMENT_SELECTOR}; constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ @@ -29,19 +27,7 @@ namespace teachos::arch::context_switching constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - 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");*/ - - kernel::cpu::call(KERNEL_CODE_POINTER); - } + auto reload_gdtr() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } auto user_mode_main() -> void { @@ -64,14 +50,11 @@ namespace teachos::arch::context_switching : "memory"); asm volatile("syscall"); - // 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);*/ + // Reading RAX decrements value by one in 32-bit compatability mode it also crashes vga write, therfore use + // SYSRETQ instead of SYSRET so we do not return into 32-bit compatability mode. + asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_number)); + video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", + video::vga::text::common_attributes::green_on_black); } auto syscall_handler() -> void @@ -103,11 +86,7 @@ namespace teachos::arch::context_switching : [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"); + asm volatile("sysretq"); } auto enable_systemcall() -> void @@ -117,8 +96,7 @@ namespace teachos::arch::context_switching kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); 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); + uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); diff --git a/arch/x86_64/src/kernel/cpu/call.cpp b/arch/x86_64/src/kernel/cpu/call.cpp index 6564b76..98fa248 100644 --- a/arch/x86_64/src/kernel/cpu/call.cpp +++ b/arch/x86_64/src/kernel/cpu/call.cpp @@ -5,6 +5,5 @@ namespace teachos::arch::kernel::cpu auto call(far_pointer pointer) -> void { asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); - // asm volatile("ljmp *%0" : : "m"(pointer)); } } // namespace teachos::arch::kernel::cpu -- cgit v1.2.3 From 5a8c9d2f2e4a3d2810f81c35070c6ef0926cfdd1 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 3 May 2025 09:45:45 +0000 Subject: write wrapper function for syscall --- .../interrupt_descriptor_table.cpp | 5 -- arch/x86_64/src/context_switching/main.cpp | 71 +++------------------- arch/x86_64/src/context_switching/syscall/main.cpp | 57 +++++++++++++++++ .../context_switching/syscall/syscall_handler.cpp | 68 +++++++++++++++++++++ .../generic_interrupt_handler.cpp | 26 -------- arch/x86_64/src/kernel/cpu/control_register.cpp | 6 -- 6 files changed, 133 insertions(+), 100 deletions(-) create mode 100644 arch/x86_64/src/context_switching/syscall/main.cpp create mode 100644 arch/x86_64/src/context_switching/syscall/syscall_handler.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp index c041198..7aa0859 100644 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp @@ -26,11 +26,6 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table interrupt_descriptor_table.at(i) = {selector, ist, flags, offset}; } - interrupt_descriptor_table.at(0x80) = { - segment_selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}, ist_offset{0U}, - idt_flags{idt_flags::DESCRIPTOR_LEVEL_USER | idt_flags::TRAP_GATE | idt_flags::PRESENT}, - uint64_t{reinterpret_cast(interrupt_handling::syscall_interrupt_handler)}}; - return interrupt_descriptor_table; } } // namespace diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 06c0810..7fe159e 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,11 +1,11 @@ #include "arch/context_switching/main.hpp" #include "arch/boot/pointers.hpp" +#include "arch/context_switching/syscall/main.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/kernel/cpu/call.hpp" #include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/msr.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" #include "arch/video/vga/text.hpp" @@ -14,10 +14,6 @@ namespace teachos::arch::context_switching { namespace { - auto constexpr IA32_STAR_ADDRESS = 0xC0000081; - auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; - auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; - constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, @@ -31,8 +27,6 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { - video::vga::text::write("Successfully entered user mode!", video::vga::text::common_attributes::green_on_black); - // RFLAGS is saved into R11, RIP of the next instruction into RCX // Required for SYSRETURN to know where to return too. // Additional state needs to be saved by calling convention: @@ -43,65 +37,16 @@ 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 syscall_number = 60U; - asm volatile("mov %[input], %%rax" - : /* no output from call */ - : [input] "r"(syscall_number) - : "memory"); - asm volatile("syscall"); - - // Reading RAX decrements value by one in 32-bit compatability mode it also crashes vga write, therfore use - // SYSRETQ instead of SYSRET so we do not return into 32-bit compatability mode. - asm volatile("mov %%rax, %[output]" : [output] "=r"(syscall_number)); - 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, 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) + const char syscall_message[32] = "Successfully entered user mode!"; + auto error = syscall::syscall(syscall::WRITE, {reinterpret_cast(&syscall_message)}); + + if (!error) { - case 1: - // Write VGA - break; - case 60U: - // Exit - break; - default: - break; + video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", + video::vga::text::common_attributes::green_on_black); } - - uint64_t result = 0U; - asm volatile("mov %[input], %%rax" - : /* no output from call */ - : [input] "r"(result) - : "memory"); - - asm volatile("sysretq"); } - - auto enable_systemcall() -> void - { - uint64_t const syscall_function = reinterpret_cast(syscall_handler); - kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - - uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); - kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); - - kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); - } - } // namespace auto initialize_descriptor_tables() -> descriptor_tables @@ -129,7 +74,7 @@ namespace teachos::arch::context_switching auto switch_to_user_mode() -> void { - enable_systemcall(); + syscall::enable_syscall(); switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user_mode_main); } diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp new file mode 100644 index 0000000..e90f503 --- /dev/null +++ b/arch/x86_64/src/context_switching/syscall/main.cpp @@ -0,0 +1,57 @@ +#include "arch/context_switching/syscall/main.hpp" + +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/exception_handling/panic.hpp" +#include "arch/kernel/cpu/msr.hpp" + +#include + +namespace teachos::arch::context_switching::syscall +{ + namespace + { + constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + + auto constexpr IA32_STAR_ADDRESS = 0xC0000081; + auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; + auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; + + } // namespace + + auto enable_syscall() -> void + { + uint64_t const syscall_function = reinterpret_cast(syscall_handler); + kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); + + uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; + uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); + kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); + + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); + } + + auto syscall(type syscall_number, arguments args) -> uint64_t + { + asm volatile("mov %[input], %%rax" + : /* no output from call */ + : [input] "m"(syscall_number) + : "memory"); + + asm volatile("mov %[input], %%rdi " : /* no output from call */ : [input] "m"(args.arg_0) : "memory"); + asm volatile("mov %[input], %%rsi" : /* no output from call */ : [input] "m"(args.arg_1) : "memory"); + asm volatile("mov %[input], %%rdx" : /* no output from call */ : [input] "m"(args.arg_2) : "memory"); + asm volatile("mov %[input], %%r10" : /* no output from call */ : [input] "m"(args.arg_3) : "memory"); + asm volatile("mov %[input], %%r8" : /* no output from call */ : [input] "m"(args.arg_4) : "memory"); + asm volatile("mov %[input], %%r9" : /* no output from call */ : [input] "m"(args.arg_5) : "memory"); + + asm volatile("syscall"); + + uint64_t result{}; + asm volatile("mov %%rax, %[output]" : [output] "=m"(result)); + return result; + } + +} // namespace teachos::arch::context_switching::syscall \ No newline at end of file diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp new file mode 100644 index 0000000..f6e1c9e --- /dev/null +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -0,0 +1,68 @@ +#include "arch/context_switching/syscall/syscall_handler.hpp" + +#include "arch/exception_handling/panic.hpp" +#include "arch/video/vga/text.hpp" + +namespace teachos::arch::context_switching::syscall +{ + + namespace + { + auto write_to_vga_buffer(uint64_t buffer) + { + video::vga::text::write(reinterpret_cast(buffer), + video::vga::text::common_attributes::green_on_black); + } + } // namespace + + auto syscall_handler() -> void + { + // Saving state of rcx and r11 because it is required by sysretq to function. + // Calls to other functions potentially overwrite these registers, because of + // callee saved calling convention. + uint64_t return_instruction_pointer, rflags = {}; + asm volatile("mov %%rcx, %[output]" : [output] "=m"(return_instruction_pointer)); + asm volatile("mov %%r11, %[output]" : [output] "=m"(rflags)); + + uint64_t syscall_number, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5 = {}; + asm volatile("mov %%rdi, %[output]" : [output] "=m"(arg_0)); + asm volatile("mov %%rsi, %[output]" : [output] "=m"(arg_1)); + asm volatile("mov %%rdx, %[output]" : [output] "=m"(arg_2)); + asm volatile("mov %%r10, %[output]" : [output] "=m"(arg_3)); + asm volatile("mov %%r8, %[output]" : [output] "=m"(arg_4)); + asm volatile("mov %%r9, %[output]" : [output] "=m"(arg_5)); + + // RAX is read last, because paired with our type enum, we can use it to check + // if the register has been written by the compiled code between executing the syscall + // and now. + asm volatile("mov %%rax, %[output]" : [output] "=m"(syscall_number)); + + switch (static_cast(syscall_number)) + { + case WRITE: + write_to_vga_buffer(arg_0); + break; + default: + teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); + break; + } + + uint64_t result = 0U; + asm volatile("mov %[input], %%rax" + : /* no output from call */ + : [input] "m"(result) + : "memory"); + + asm volatile("mov %[input], %%rcx" + : /* no output from call */ + : [input] "m"(return_instruction_pointer) + : "memory"); + asm volatile("mov %[input], %%r11" + : /* no output from call */ + : [input] "m"(rflags) + : "memory"); + + asm volatile("sysretq"); + } + +} // namespace teachos::arch::context_switching::syscall \ No newline at end of file diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp index 60fb50c..8e2c62d 100644 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -9,30 +9,4 @@ namespace teachos::arch::interrupt_handling (void)frame; video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); } - - auto syscall_interrupt_handler(interrupt_frame * frame) -> void - { - // RDI, RSI, RDX, RCX, R8, R9 - // RDI -> SYSCALL number - // Others are arguments - - // TODO: The registers are not available here. We need to set them up on the stack - // and access them via argument. - - uint64_t syscall_number{}; - asm volatile("mov %%rdi, %0" : "=r"(syscall_number)); - - // Handle system call based on the number - switch (syscall_number) - { - case 1: - video::vga::text::write("SYSCALL 1.", video::vga::text::common_attributes::green_on_black); - break; - default: - // Handle unknown syscall - break; - } - - (void)frame; - } } // namespace teachos::arch::interrupt_handling diff --git a/arch/x86_64/src/kernel/cpu/control_register.cpp b/arch/x86_64/src/kernel/cpu/control_register.cpp index a39a360..41b8cd7 100644 --- a/arch/x86_64/src/kernel/cpu/control_register.cpp +++ b/arch/x86_64/src/kernel/cpu/control_register.cpp @@ -23,9 +23,6 @@ namespace teachos::arch::kernel::cpu 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; } @@ -58,9 +55,6 @@ namespace teachos::arch::kernel::cpu : [input] "r"(new_value) : "memory"); break; - default: - exception_handling::panic("[Control Register] Attempted to write non-existent or reserved control register"); - break; } } -- cgit v1.2.3 From 4b4ca98376cb4bdf97fd910b7e2ca78628b0a8ee Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 3 May 2025 09:51:15 +0000 Subject: rename syscall result variable --- arch/x86_64/src/context_switching/syscall/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp index e90f503..9ac63ce 100644 --- a/arch/x86_64/src/context_switching/syscall/main.cpp +++ b/arch/x86_64/src/context_switching/syscall/main.cpp @@ -49,9 +49,9 @@ namespace teachos::arch::context_switching::syscall asm volatile("syscall"); - uint64_t result{}; - asm volatile("mov %%rax, %[output]" : [output] "=m"(result)); - return result; + uint64_t error{}; + asm volatile("mov %%rax, %[output]" : [output] "=m"(error)); + return error; } } // namespace teachos::arch::context_switching::syscall \ No newline at end of file -- cgit v1.2.3 From 4d4e23116284f41329ea809e2bda86feea1b325c Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 4 May 2025 10:51:12 +0000 Subject: fix returning from syscall --- arch/x86_64/src/context_switching/main.cpp | 3 ++- arch/x86_64/src/context_switching/syscall/syscall_handler.cpp | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 7fe159e..6c6ec1a 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -27,6 +27,7 @@ namespace teachos::arch::context_switching auto user_mode_main() -> void { + // TODO: Remove or replace this wall of text // RFLAGS is saved into R11, RIP of the next instruction into RCX // Required for SYSRETURN to know where to return too. // Additional state needs to be saved by calling convention: @@ -38,7 +39,7 @@ 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 - const char syscall_message[32] = "Successfully entered user mode!"; + const char syscall_message[68] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; auto error = syscall::syscall(syscall::WRITE, {reinterpret_cast(&syscall_message)}); if (!error) diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index f6e1c9e..759a092 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -12,6 +12,7 @@ namespace teachos::arch::context_switching::syscall { video::vga::text::write(reinterpret_cast(buffer), video::vga::text::common_attributes::green_on_black); + video::vga::text::newline(); } } // namespace @@ -62,7 +63,8 @@ namespace teachos::arch::context_switching::syscall : [input] "m"(rflags) : "memory"); - asm volatile("sysretq"); + asm volatile("leave\n" + "sysretq"); } } // namespace teachos::arch::context_switching::syscall \ No newline at end of file -- cgit v1.2.3 From ccb0fcb78c0d22ebaeb9aa37f1941b0d44c98038 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 4 May 2025 11:07:48 +0000 Subject: move user-mode code into own namespace and linker section --- arch/x86_64/src/context_switching/main.cpp | 27 ++-------------------- arch/x86_64/src/user/main.cpp | 36 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 25 deletions(-) create mode 100644 arch/x86_64/src/user/main.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index 6c6ec1a..a112924 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -8,6 +8,7 @@ #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" +#include "arch/user/main.hpp" #include "arch/video/vga/text.hpp" namespace teachos::arch::context_switching @@ -24,30 +25,6 @@ namespace teachos::arch::context_switching 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; auto reload_gdtr() -> void { kernel::cpu::call(KERNEL_CODE_POINTER); } - - auto user_mode_main() -> void - { - // TODO: Remove or replace this wall of text - // RFLAGS is saved into R11, RIP of the next instruction into RCX - // Required for SYSRETURN to know where to return too. - // Additional state needs to be saved by calling convention: - - // Syscall Number: RAX, Return Value: RAX (0 indicating no error, and -1 indicating an error, use as a boolean) - // Argument in this order (max 6. no argument on stack): RDI, RSI, RDX, R10, R8, R9 - // Not used registers: RBX, RSP, R12, R13, R14 - - // 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 - - const char syscall_message[68] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; - auto error = syscall::syscall(syscall::WRITE, {reinterpret_cast(&syscall_message)}); - - if (!error) - { - video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", - video::vga::text::common_attributes::green_on_black); - } - } } // namespace auto initialize_descriptor_tables() -> descriptor_tables @@ -76,7 +53,7 @@ namespace teachos::arch::context_switching auto switch_to_user_mode() -> void { syscall::enable_syscall(); - switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user_mode_main); + switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user::main); } auto switch_context(interrupt_descriptor_table::segment_selector data_segment, diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp new file mode 100644 index 0000000..6d8eea7 --- /dev/null +++ b/arch/x86_64/src/user/main.cpp @@ -0,0 +1,36 @@ +#include "arch/user/main.hpp" + +#include "arch/context_switching/syscall/main.hpp" + +// TODO: Disallow this import +#include "arch/video/vga/text.hpp" + +namespace teachos::arch::user +{ + + [[gnu::section(".user_text")]] + auto main() -> void + { + // TODO: Remove or replace this wall of text + // RFLAGS is saved into R11, RIP of the next instruction into RCX + // Required for SYSRETURN to know where to return too. + // Additional state needs to be saved by calling convention: + + // Syscall Number: RAX, Return Value: RAX (0 indicating no error, and -1 indicating an error, use as a boolean) + // Argument in this order (max 6. no argument on stack): RDI, RSI, RDX, R10, R8, R9 + // Not used registers: RBX, RSP, R12, R13, R14 + + // 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 + + const char syscall_message[68] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; + auto error = context_switching::syscall::syscall(context_switching::syscall::WRITE, + {reinterpret_cast(&syscall_message)}); + + if (!error) + { + video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", + video::vga::text::common_attributes::green_on_black); + } + } +} // namespace teachos::arch::user \ No newline at end of file -- cgit v1.2.3 From c1dff44858ebdb3cd5a49e84179796e44e7eb91c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 5 May 2025 06:41:31 +0000 Subject: Fix recursive include using extra file --- arch/x86_64/src/context_switching/main.cpp | 5 +--- arch/x86_64/src/context_switching/syscall/main.cpp | 35 ++-------------------- .../context_switching/syscall/syscall_enable.cpp | 32 ++++++++++++++++++++ .../context_switching/syscall/syscall_handler.cpp | 13 +++++--- arch/x86_64/src/user/main.cpp | 7 ++--- 5 files changed, 47 insertions(+), 45 deletions(-) create mode 100644 arch/x86_64/src/context_switching/syscall/syscall_enable.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp index a112924..9539428 100644 --- a/arch/x86_64/src/context_switching/main.cpp +++ b/arch/x86_64/src/context_switching/main.cpp @@ -1,15 +1,12 @@ #include "arch/context_switching/main.hpp" #include "arch/boot/pointers.hpp" -#include "arch/context_switching/syscall/main.hpp" -#include "arch/exception_handling/assert.hpp" +#include "arch/context_switching/syscall/syscall_enable.hpp" #include "arch/kernel/cpu/call.hpp" -#include "arch/kernel/cpu/control_register.hpp" #include "arch/kernel/cpu/if.hpp" #include "arch/kernel/cpu/segment_register.hpp" #include "arch/kernel/cpu/tr.hpp" #include "arch/user/main.hpp" -#include "arch/video/vga/text.hpp" namespace teachos::arch::context_switching { diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp index 9ac63ce..a226e23 100644 --- a/arch/x86_64/src/context_switching/syscall/main.cpp +++ b/arch/x86_64/src/context_switching/syscall/main.cpp @@ -1,39 +1,8 @@ #include "arch/context_switching/syscall/main.hpp" -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/exception_handling/panic.hpp" -#include "arch/kernel/cpu/msr.hpp" - -#include - namespace teachos::arch::context_switching::syscall { - namespace - { - constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ - 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - - auto constexpr IA32_STAR_ADDRESS = 0xC0000081; - auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; - auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; - - } // namespace - - auto enable_syscall() -> void - { - uint64_t const syscall_function = reinterpret_cast(syscall_handler); - kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - - uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); - kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); - - kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); - } - - auto syscall(type syscall_number, arguments args) -> uint64_t + auto syscall(type syscall_number, arguments args) -> error { asm volatile("mov %[input], %%rax" : /* no output from call */ @@ -49,7 +18,7 @@ namespace teachos::arch::context_switching::syscall asm volatile("syscall"); - uint64_t error{}; + error error{}; asm volatile("mov %%rax, %[output]" : [output] "=m"(error)); return error; } diff --git a/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp b/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp new file mode 100644 index 0000000..e6265d3 --- /dev/null +++ b/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp @@ -0,0 +1,32 @@ +#include "arch/context_switching/syscall/syscall_enable.hpp" + +#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" +#include "arch/context_switching/syscall/syscall_handler.hpp" +#include "arch/kernel/cpu/msr.hpp" + +namespace teachos::arch::context_switching::syscall +{ + namespace + { + constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ + 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; + + auto constexpr IA32_STAR_ADDRESS = 0xC0000081; + auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; + auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; + + } // namespace + + auto enable_syscall() -> void + { + uint64_t const syscall_function = reinterpret_cast(syscall_handler); + kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); + kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); + + uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; + uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); + kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); + + kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); + } +} // namespace teachos::arch::context_switching::syscall \ No newline at end of file diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index 759a092..fbfecc0 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -1,5 +1,6 @@ #include "arch/context_switching/syscall/syscall_handler.hpp" +#include "arch/context_switching/syscall/main.hpp" #include "arch/exception_handling/panic.hpp" #include "arch/video/vga/text.hpp" @@ -8,11 +9,12 @@ namespace teachos::arch::context_switching::syscall namespace { - auto write_to_vga_buffer(uint64_t buffer) + auto write_to_vga_buffer(uint64_t buffer) -> error { video::vga::text::write(reinterpret_cast(buffer), video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); + return error::OK; } } // namespace @@ -38,17 +40,17 @@ namespace teachos::arch::context_switching::syscall // and now. asm volatile("mov %%rax, %[output]" : [output] "=m"(syscall_number)); + error result = error::OK; switch (static_cast(syscall_number)) { - case WRITE: - write_to_vga_buffer(arg_0); + case type::WRITE: + result = write_to_vga_buffer(arg_0); break; default: teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); break; } - uint64_t result = 0U; asm volatile("mov %[input], %%rax" : /* no output from call */ : [input] "m"(result) @@ -63,6 +65,9 @@ namespace teachos::arch::context_switching::syscall : [input] "m"(rflags) : "memory"); + // Additionally call leave, because x86 allocates tack space for the internal variables. If we do not clean up this + // newly created stack frame the syscall instruction that landed in this syscall_handler, will never return to the + // method that originally called it, becuase the RIP has not been restored from the previous stack frame. asm volatile("leave\n" "sysretq"); } diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 6d8eea7..8ce21ba 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -7,7 +7,6 @@ namespace teachos::arch::user { - [[gnu::section(".user_text")]] auto main() -> void { @@ -23,9 +22,9 @@ namespace teachos::arch::user // 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 - const char syscall_message[68] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; - auto error = context_switching::syscall::syscall(context_switching::syscall::WRITE, - {reinterpret_cast(&syscall_message)}); + char constexpr syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; + auto const error = context_switching::syscall::syscall(context_switching::syscall::type::WRITE, + {reinterpret_cast(&syscall_message)}); if (!error) { -- cgit v1.2.3 From 27d4fb90ebbc754e98ff68ce5bc7839a44ed99c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 5 May 2025 09:22:28 +0000 Subject: Add comments to syscall components --- arch/x86_64/src/context_switching/syscall/main.cpp | 2 +- arch/x86_64/src/context_switching/syscall/syscall_enable.cpp | 4 ++-- arch/x86_64/src/context_switching/syscall/syscall_handler.cpp | 2 +- arch/x86_64/src/user/main.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp index a226e23..93fc613 100644 --- a/arch/x86_64/src/context_switching/syscall/main.cpp +++ b/arch/x86_64/src/context_switching/syscall/main.cpp @@ -23,4 +23,4 @@ namespace teachos::arch::context_switching::syscall return error; } -} // namespace teachos::arch::context_switching::syscall \ No newline at end of file +} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp b/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp index e6265d3..3c43336 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp @@ -8,7 +8,7 @@ namespace teachos::arch::context_switching::syscall { namespace { - constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ + interrupt_descriptor_table::segment_selector constexpr KERNEL_CODE_SEGMENT_SELECTOR{ 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; auto constexpr IA32_STAR_ADDRESS = 0xC0000081; @@ -29,4 +29,4 @@ namespace teachos::arch::context_switching::syscall kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); } -} // namespace teachos::arch::context_switching::syscall \ No newline at end of file +} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index fbfecc0..da9eb1b 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -72,4 +72,4 @@ namespace teachos::arch::context_switching::syscall "sysretq"); } -} // namespace teachos::arch::context_switching::syscall \ No newline at end of file +} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 8ce21ba..1d56d2e 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -32,4 +32,4 @@ namespace teachos::arch::user video::vga::text::common_attributes::green_on_black); } } -} // namespace teachos::arch::user \ No newline at end of file +} // namespace teachos::arch::user -- cgit v1.2.3 From 7d2e8bc16e6c1bacb3c676d21ea2245d8132218f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 5 May 2025 11:27:29 +0000 Subject: Remove the addition of USER_ACCESSIBLE flag to every entry created --- arch/x86_64/src/memory/main.cpp | 3 ++- arch/x86_64/src/memory/paging/inactive_page_table.cpp | 2 +- arch/x86_64/src/memory/paging/page_entry.cpp | 10 ++++------ arch/x86_64/src/memory/paging/temporary_page.cpp | 10 +++++----- arch/x86_64/src/user/main.cpp | 12 ------------ 5 files changed, 12 insertions(+), 25 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index bd094e0..4cccabb 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -31,7 +31,8 @@ namespace teachos::arch::memory for (auto const & page : pages) { - active_table.map_page_to_next_free_frame(allocator, page, paging::entry::WRITABLE); + active_table.map_page_to_next_free_frame(allocator, page, + paging::entry::WRITABLE | paging::entry::USER_ACCESSIBLE); } } } // namespace diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp index 4e0610e..780f12c 100644 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -14,7 +14,7 @@ namespace teachos::arch::memory::paging { auto table = temporary_page.map_table_frame(page_table_level_4_frame, active_page_table); table.zero_entries(); - table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); + table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE | entry::USER_ACCESSIBLE); temporary_page.unmap_page(active_page_table); } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 3a0f03f..c76c673 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -10,7 +10,7 @@ namespace teachos::arch::memory::paging } // namespace entry::entry(uint64_t flags) - : flags(flags | entry::USER_ACCESSIBLE) // TODO: Temporarily make all entries user accessible + : flags(flags) { // Nothing to do. } @@ -31,15 +31,14 @@ namespace teachos::arch::memory::paging { flags |= entry::EXECUTING_CODE_FORBIDDEN; } - - // TODO: Temporarily make all entries user accessible - flags |= entry::USER_ACCESSIBLE; } auto entry::is_unused() const -> bool { return flags == 0U; } auto entry::set_unused() -> void { flags = 0U; } + auto entry::set_user_accesible() -> void { flags |= entry::USER_ACCESSIBLE; } + auto entry::calculate_pointed_to_frame() const -> std::optional { if (contains_flags(PRESENT)) @@ -57,8 +56,7 @@ namespace teachos::arch::memory::paging exception_handling::assert((frame.start_address() & ~PHYSICAL_ADDRESS_MASK) == 0, "[Paging Entry] Start address is not aligned with page"); - // TODO: Temporarily make all entries user accessible - flags = frame.start_address() | additional_flags.to_ulong() | entry::USER_ACCESSIBLE; + flags = frame.start_address() | additional_flags.to_ulong(); } auto entry::get_flags() const -> std::bitset<64U> { return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; } diff --git a/arch/x86_64/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp index 152241d..9946f36 100644 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -4,21 +4,21 @@ namespace teachos::arch::memory::paging { - auto temporary_page::map_table_frame(allocator::physical_frame frame, - active_page_table & active_table) -> page_table_handle + auto temporary_page::map_table_frame(allocator::physical_frame frame, active_page_table & active_table) + -> page_table_handle { page_table_handle handle{reinterpret_cast(map_to_frame(frame, active_table)), page_table_handle::LEVEL1}; return handle; } - auto temporary_page::map_to_frame(allocator::physical_frame frame, - active_page_table & active_table) -> virtual_address + auto temporary_page::map_to_frame(allocator::physical_frame frame, active_page_table & active_table) + -> virtual_address { exception_handling::assert(!active_table.translate_page(page).has_value(), "[Temporary page] Page is already mapped"); - active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE); + active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE | entry::USER_ACCESSIBLE); return page.start_address(); } diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 1d56d2e..3ddcb32 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -10,18 +10,6 @@ namespace teachos::arch::user [[gnu::section(".user_text")]] auto main() -> void { - // TODO: Remove or replace this wall of text - // RFLAGS is saved into R11, RIP of the next instruction into RCX - // Required for SYSRETURN to know where to return too. - // Additional state needs to be saved by calling convention: - - // Syscall Number: RAX, Return Value: RAX (0 indicating no error, and -1 indicating an error, use as a boolean) - // Argument in this order (max 6. no argument on stack): RDI, RSI, RDX, R10, R8, R9 - // Not used registers: RBX, RSP, R12, R13, R14 - - // 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 - char constexpr syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; auto const error = context_switching::syscall::syscall(context_switching::syscall::type::WRITE, {reinterpret_cast(&syscall_message)}); -- cgit v1.2.3 From c9f46f3773e7943ce114af888a44f50061c2ac1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 6 May 2025 13:40:42 +0000 Subject: Remove user Mode Access to VGA / Heap and Kernel Methods. --- .../src/interrupt_handling/generic_interrupt_handler.cpp | 1 + arch/x86_64/src/memory/main.cpp | 3 +-- arch/x86_64/src/memory/paging/inactive_page_table.cpp | 2 +- arch/x86_64/src/memory/paging/temporary_page.cpp | 2 +- arch/x86_64/src/user/main.cpp | 12 +++++++++++- 5 files changed, 15 insertions(+), 5 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp index 8e2c62d..9d061a8 100644 --- a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp +++ b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp @@ -8,5 +8,6 @@ namespace teachos::arch::interrupt_handling { (void)frame; video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); + video::vga::text::newline(); } } // namespace teachos::arch::interrupt_handling diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 4cccabb..bd094e0 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -31,8 +31,7 @@ namespace teachos::arch::memory for (auto const & page : pages) { - active_table.map_page_to_next_free_frame(allocator, page, - paging::entry::WRITABLE | paging::entry::USER_ACCESSIBLE); + active_table.map_page_to_next_free_frame(allocator, page, paging::entry::WRITABLE); } } } // namespace diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp index 780f12c..4e0610e 100644 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -14,7 +14,7 @@ namespace teachos::arch::memory::paging { auto table = temporary_page.map_table_frame(page_table_level_4_frame, active_page_table); table.zero_entries(); - table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE | entry::USER_ACCESSIBLE); + table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); temporary_page.unmap_page(active_page_table); } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp index 9946f36..8e73523 100644 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -18,7 +18,7 @@ namespace teachos::arch::memory::paging exception_handling::assert(!active_table.translate_page(page).has_value(), "[Temporary page] Page is already mapped"); - active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE | entry::USER_ACCESSIBLE); + active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE); return page.start_address(); } diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 3ddcb32..3e7b0ec 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -3,21 +3,31 @@ #include "arch/context_switching/syscall/main.hpp" // TODO: Disallow this import +#include "arch/kernel/cpu/if.hpp" #include "arch/video/vga/text.hpp" namespace teachos::arch::user { - [[gnu::section(".user_text")]] auto main() -> void { char constexpr syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; auto const error = context_switching::syscall::syscall(context_switching::syscall::type::WRITE, {reinterpret_cast(&syscall_message)}); + kernel::cpu::clear_interrupt_flag(); // Causes crash Kernel Code (.text) is not mapped in User mMde + + auto test = new int{20}; // Causes crash Heap is not mapped in User Mode + (void)test; + if (!error) { + // Causes crash vga is not mapped in User Mode video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", video::vga::text::common_attributes::green_on_black); } + + for (;;) + { + } } } // namespace teachos::arch::user -- cgit v1.2.3 From be32189323ba8c46091d6deaf091cf41147426b4 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Wed, 7 May 2025 14:06:25 +0000 Subject: wip custom heap allocation functions for user mode --- .../src/memory/heap/global_heap_allocator.cpp | 54 +++++++++++++++------- arch/x86_64/src/memory/main.cpp | 6 +-- arch/x86_64/src/user/main.cpp | 26 ++++++----- 3 files changed, 55 insertions(+), 31 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index c1ca160..51f6261 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -6,15 +6,20 @@ namespace teachos::arch::memory::heap { - heap_allocator * global_heap_allocator::allocator_instance = nullptr; + heap_allocator * global_heap_allocator::kernel_allocator_instance = nullptr; + heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; - auto global_heap_allocator::allocate(std::size_t size) -> void * { return get().allocate(size); } + auto global_heap_allocator::kmalloc(std::size_t size) -> void * { return kernel().allocate(size); } - auto global_heap_allocator::deallocate(void * pointer) noexcept -> void { get().deallocate(pointer); } + auto global_heap_allocator::kfree(void * pointer) noexcept -> void { kernel().deallocate(pointer); } + + auto global_heap_allocator::malloc(std::size_t size) -> void * { return user().allocate(size); } + + auto global_heap_allocator::free(void * pointer) noexcept -> void { user().deallocate(pointer); } auto global_heap_allocator::register_heap_allocator(heap_allocator_type new_type) -> void { - exception_handling::assert(allocator_instance == nullptr, + exception_handling::assert(kernel_allocator_instance == nullptr, "Calling register_heap_allocator_type can only be done once."); switch (new_type) @@ -23,56 +28,71 @@ namespace teachos::arch::memory::heap // Nothing to do break; case heap_allocator_type::BUMP: { - static bump_allocator allocator{HEAP_START, HEAP_START + HEAP_SIZE}; - allocator_instance = &allocator; + static bump_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; + kernel_allocator_instance = &kernel_allocator; + + static bump_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; + user_allocator_instance = &user_allocator; break; } case heap_allocator_type::LINKED_LIST: { - static linked_list_allocator allocator{HEAP_START, HEAP_START + HEAP_SIZE}; - allocator_instance = &allocator; + static linked_list_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; + kernel_allocator_instance = &kernel_allocator; + + static linked_list_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; + user_allocator_instance = &user_allocator; break; } } } - auto global_heap_allocator::get() -> heap_allocator & + auto global_heap_allocator::kernel() -> heap_allocator & + { + exception_handling::assert(kernel_allocator_instance != nullptr, + "Attempted to allocate or deallocate using the global_heap_allocator before " + "register_heap_allocation_type was called."); + + return *kernel_allocator_instance; + } + + auto global_heap_allocator::user() -> heap_allocator & { - exception_handling::assert(allocator_instance != nullptr, + exception_handling::assert(user_allocator_instance != nullptr, "Attempted to allocate or deallocate using the global_heap_allocator before " "register_heap_allocation_type was called."); - return *allocator_instance; + return *user_allocator_instance; } } // namespace teachos::arch::memory::heap auto operator new(std::size_t size) -> void * { - return teachos::arch::memory::heap::global_heap_allocator::allocate(size); + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); } auto operator delete(void * pointer) noexcept -> void { - teachos::arch::memory::heap::global_heap_allocator::deallocate(pointer); + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); } auto operator delete(void * pointer, std::size_t size) noexcept -> void { (void)size; - teachos::arch::memory::heap::global_heap_allocator::deallocate(pointer); + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); } auto operator new[](std::size_t size) -> void * { - return teachos::arch::memory::heap::global_heap_allocator::allocate(size); + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); } auto operator delete[](void * pointer) noexcept -> void { - teachos::arch::memory::heap::global_heap_allocator::deallocate(pointer); + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); } auto operator delete[](void * pointer, std::size_t size) noexcept -> void { (void)size; - teachos::arch::memory::heap::global_heap_allocator::deallocate(pointer); + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); } diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index bd094e0..558fbce 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -5,7 +5,7 @@ #include "arch/kernel/cpu/msr.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/allocator/concept.hpp" -#include "arch/memory/heap/heap_allocator.hpp" +#include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" @@ -22,9 +22,9 @@ namespace teachos::arch::memory template auto remap_heap(T & allocator, paging::active_page_table & active_table) -> void { - auto const start_page = paging::virtual_page::containing_address(memory::heap::HEAP_START); + auto const start_page = paging::virtual_page::containing_address(heap::KERNEL_HEAP_START); auto const end_page = - ++(paging::virtual_page::containing_address(memory::heap::HEAP_START + memory::heap::HEAP_SIZE - 1)); + ++(paging::virtual_page::containing_address(heap::KERNEL_HEAP_START + heap::KERNEL_HEAP_SIZE - 1)); paging::page_container::iterator const begin{start_page}; paging::page_container::iterator const end{end_page}; paging::page_container const pages{begin, end}; diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 3e7b0ec..4f6e688 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -1,8 +1,9 @@ #include "arch/user/main.hpp" #include "arch/context_switching/syscall/main.hpp" +#include "arch/memory/heap/global_heap_allocator.hpp" -// TODO: Disallow this import +// TODO: Disallow these imports #include "arch/kernel/cpu/if.hpp" #include "arch/video/vga/text.hpp" @@ -11,20 +12,23 @@ namespace teachos::arch::user auto main() -> void { char constexpr syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; - auto const error = context_switching::syscall::syscall(context_switching::syscall::type::WRITE, - {reinterpret_cast(&syscall_message)}); + context_switching::syscall::syscall(context_switching::syscall::type::WRITE, + {reinterpret_cast(&syscall_message)}); - kernel::cpu::clear_interrupt_flag(); // Causes crash Kernel Code (.text) is not mapped in User mMde + // kernel::cpu::clear_interrupt_flag(); // Causes crash Kernel Code (.text) is not mapped in User mMde - auto test = new int{20}; // Causes crash Heap is not mapped in User Mode + auto test = memory::heap::global_heap_allocator::malloc(20U); (void)test; - if (!error) - { - // Causes crash vga is not mapped in User Mode - video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", - video::vga::text::common_attributes::green_on_black); - } + // auto test = new int{20}; // Causes crash Heap is not mapped in User Mode + // (void)test; + + // if (!error) + // { + // // Causes crash vga is not mapped in User Mode + // video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", + // video::vga::text::common_attributes::green_on_black); + // } for (;;) { -- cgit v1.2.3 From 0b62fdb3fe657d056a42d7567b67951ba3468738 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Thu, 8 May 2025 08:51:52 +0000 Subject: wip allocating heap memory in user mode --- arch/x86_64/src/kernel/main.cpp | 3 ++ .../src/memory/heap/global_heap_allocator.cpp | 20 ++++---- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 55 ++++++++++++++++++++++ arch/x86_64/src/memory/main.cpp | 18 ++++--- arch/x86_64/src/user/main.cpp | 4 +- 5 files changed, 81 insertions(+), 19 deletions(-) create mode 100644 arch/x86_64/src/memory/heap/user_heap_allocator.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 05c879e..43b5f90 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -63,6 +63,9 @@ namespace teachos::arch::kernel memory::heap::global_heap_allocator::register_heap_allocator(memory::heap::heap_allocator_type::LINKED_LIST); // heap_test(); + auto address = memory::heap::global_heap_allocator::kmalloc(8U); + (void)address; + context_switching::switch_to_user_mode(); } } // namespace teachos::arch::kernel diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index 51f6261..acba02d 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -3,11 +3,12 @@ #include "arch/exception_handling/assert.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/linked_list_allocator.hpp" +#include "arch/memory/heap/user_heap_allocator.hpp" namespace teachos::arch::memory::heap { heap_allocator * global_heap_allocator::kernel_allocator_instance = nullptr; - heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; + user_heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; auto global_heap_allocator::kmalloc(std::size_t size) -> void * { return kernel().allocate(size); } @@ -30,20 +31,17 @@ namespace teachos::arch::memory::heap case heap_allocator_type::BUMP: { static bump_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; kernel_allocator_instance = &kernel_allocator; - - static bump_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; - user_allocator_instance = &user_allocator; break; } case heap_allocator_type::LINKED_LIST: { static linked_list_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; kernel_allocator_instance = &kernel_allocator; - - static linked_list_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; - user_allocator_instance = &user_allocator; break; } } + + static user_heap_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; + user_allocator_instance = &user_allocator; } auto global_heap_allocator::kernel() -> heap_allocator & @@ -55,11 +53,11 @@ namespace teachos::arch::memory::heap return *kernel_allocator_instance; } - auto global_heap_allocator::user() -> heap_allocator & + auto global_heap_allocator::user() -> user_heap_allocator & { - exception_handling::assert(user_allocator_instance != nullptr, - "Attempted to allocate or deallocate using the global_heap_allocator before " - "register_heap_allocation_type was called."); + // exception_handling::assert(user_allocator_instance != nullptr, + // "Attempted to allocate or deallocate using the global_heap_allocator before " + // "register_heap_allocation_type was called."); return *user_allocator_instance; } diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp new file mode 100644 index 0000000..f09811d --- /dev/null +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -0,0 +1,55 @@ +#include "arch/memory/heap/user_heap_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" + +#include +#include + +namespace teachos::arch::memory::heap +{ + namespace + { + template + [[gnu::section(".user_text")]] + auto saturating_add(T x, T y) -> T + requires std::is_unsigned_v + { + if (x > std::numeric_limits::max() - y) + { + return std::numeric_limits::max(); + } + T result = x + y; + return result; + } + } // namespace + + auto user_heap_allocator::allocate(std::size_t size) -> void * + { + // Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the + // exchange failed, becuase the value was not the expected one. + auto alloc_start = next.load(std::memory_order::relaxed); + // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time + // causing the value to differ and the calculation to have to be redone. + for (;;) + { + auto const alloc_end = saturating_add(alloc_start, size); + arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory"); + // Check if the atomic value is still the one initally loaded, if it isn't we have been overtaken by another + // thread and need to redo the calculation. Spurious failure by weak can be ignored, because the whole allocation + // is wrapped in an infinite for loop so a failure that wasn't actually one will simply be retried until it works. + auto const updated = next.compare_exchange_weak(alloc_start, alloc_end, std::memory_order::relaxed); + if (updated) + { + return reinterpret_cast(alloc_start); + } + } + } + + auto user_heap_allocator::deallocate(void * pointer) noexcept -> void + { + if (pointer) + { + } + } + +} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 558fbce..4cdfa80 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -20,18 +20,23 @@ namespace teachos::arch::memory } template - auto remap_heap(T & allocator, paging::active_page_table & active_table) -> void + auto remap_heap(T & allocator, paging::active_page_table & active_table, bool is_user_heap = false) -> void { - auto const start_page = paging::virtual_page::containing_address(heap::KERNEL_HEAP_START); - auto const end_page = - ++(paging::virtual_page::containing_address(heap::KERNEL_HEAP_START + heap::KERNEL_HEAP_SIZE - 1)); + auto const heap_start = is_user_heap ? heap::USER_HEAP_START : heap::KERNEL_HEAP_START; + auto const heap_size = is_user_heap ? heap::USER_HEAP_SIZE : heap::KERNEL_HEAP_SIZE; + + auto const start_page = paging::virtual_page::containing_address(heap_start); + auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); paging::page_container::iterator const begin{start_page}; paging::page_container::iterator const end{end_page}; paging::page_container const pages{begin, end}; + constexpr auto base_flags = paging::entry::WRITABLE; + auto const flags = is_user_heap ? base_flags | paging::entry::USER_ACCESSIBLE : base_flags; + for (auto const & page : pages) { - active_table.map_page_to_next_free_frame(allocator, page, paging::entry::WRITABLE); + active_table.map_page_to_next_free_frame(allocator, page, flags); } } } // namespace @@ -54,7 +59,8 @@ namespace teachos::arch::memory video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); - remap_heap(allocator, active_table); + remap_heap(allocator, active_table); // Remap kernel heap + remap_heap(allocator, active_table, true); // Remap user heap video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); } diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 4f6e688..59647f8 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -17,8 +17,8 @@ namespace teachos::arch::user // kernel::cpu::clear_interrupt_flag(); // Causes crash Kernel Code (.text) is not mapped in User mMde - auto test = memory::heap::global_heap_allocator::malloc(20U); - (void)test; + auto address = memory::heap::global_heap_allocator::malloc(8U); + (void)address; // auto test = new int{20}; // Causes crash Heap is not mapped in User Mode // (void)test; -- cgit v1.2.3 From d80ecf29baada6242c5181adaec0d1500707cad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 9 May 2025 12:00:23 +0000 Subject: Move necessary code into user text --- arch/x86_64/src/memory/heap/global_heap_allocator.cpp | 3 +++ arch/x86_64/src/memory/heap/user_heap_allocator.cpp | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index acba02d..23e2458 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -40,6 +40,7 @@ namespace teachos::arch::memory::heap } } + [[gnu::section(".user_data")]] static user_heap_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; user_allocator_instance = &user_allocator; } @@ -55,6 +56,8 @@ namespace teachos::arch::memory::heap auto global_heap_allocator::user() -> user_heap_allocator & { + // TODO: Assert Method does not exist in .user_text meaning this causes a Page Fault when accessed, Make it into a + // syscall instead // exception_handling::assert(user_allocator_instance != nullptr, // "Attempted to allocate or deallocate using the global_heap_allocator before " // "register_heap_allocation_type was called."); diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index f09811d..eefcab5 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -25,7 +25,10 @@ namespace teachos::arch::memory::heap auto user_heap_allocator::allocate(std::size_t size) -> void * { - // Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the + // TODO: .load() crashes because it is only in the kernel .text section and not the user one? How would you fix + // Similarly assert cause a crash here it is easier though simply create a syscall for the assert method. + + // that? Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the // exchange failed, becuase the value was not the expected one. auto alloc_start = next.load(std::memory_order::relaxed); // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time -- cgit v1.2.3 From a5812be4fa8ecc208219682204b14969d7b718b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 9 May 2025 13:15:58 +0000 Subject: Switch uer heap to linked list allocator --- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 186 +++++++++++++++++---- 1 file changed, 154 insertions(+), 32 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index eefcab5..6843d66 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -1,58 +1,180 @@ #include "arch/memory/heap/user_heap_allocator.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/exception_handling/panic.hpp" -#include -#include +#include namespace teachos::arch::memory::heap { - namespace + user_heap_allocator::user_heap_allocator(std::size_t heap_start, std::size_t heap_end) + : heap_start(heap_start) + , heap_end(heap_end) + , first(nullptr) + , mutex{stl::mutex{}} { - template - [[gnu::section(".user_text")]] - auto saturating_add(T x, T y) -> T - requires std::is_unsigned_v + auto const heap_size = heap_end - heap_start; + exception_handling::assert( + heap_size > min_allocatable_size(), + "[Linked List Allocator] Total heap size can not be smaller than minimum of 16 bytes to hold " + "atleast one memory hole entry"); + first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); + } + + auto user_heap_allocator::allocate(std::size_t size) -> void * + { + // Add size of size_t to the total allocated size, because we add a header that includes the size of the allocated + // block, to allow for deallocation without the need to call with the corresponding size + auto const total_size = size + sizeof(std::size_t); + mutex.lock(); + + memory_block * previous = nullptr; + auto current = first; + + while (current != nullptr) { - if (x > std::numeric_limits::max() - y) + // TODO: Can not access current pointer. Results in a General Protection Fault? + if (current->size == total_size) { - return std::numeric_limits::max(); + auto const memory_address = remove_free_memory_block(previous, current); + new (memory_address) std::size_t(total_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); } - T result = x + y; - return result; + else if (current->size >= total_size + min_allocatable_size()) + { + // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards + // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if + // the total size was less and simply deallocate it as well + auto const max_size = std::max(total_size, min_allocatable_size()); + auto const memory_address = split_free_memory_block(previous, current, max_size); + new (memory_address) std::size_t(max_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + + previous = current; + current = current->next; } - } // namespace - auto user_heap_allocator::allocate(std::size_t size) -> void * + exception_handling::panic("[Linked List Allocator] Out of memory"); + } + + auto user_heap_allocator::deallocate(void * pointer) noexcept -> void { - // TODO: .load() crashes because it is only in the kernel .text section and not the user one? How would you fix - // Similarly assert cause a crash here it is easier though simply create a syscall for the assert method. - - // that? Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the - // exchange failed, becuase the value was not the expected one. - auto alloc_start = next.load(std::memory_order::relaxed); - // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time - // causing the value to differ and the calculation to have to be redone. - for (;;) + mutex.lock(); + + // Read configured header size of the complete allocated block + auto const header_pointer = reinterpret_cast(reinterpret_cast(pointer) - sizeof(std::size_t)); + auto const total_size = *reinterpret_cast(header_pointer); + + auto const start_address = reinterpret_cast(header_pointer); + auto const end_address = start_address + total_size; + + memory_block * previous = nullptr; + auto current = first; + + while (current != nullptr) { - auto const alloc_end = saturating_add(alloc_start, size); - arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory"); - // Check if the atomic value is still the one initally loaded, if it isn't we have been overtaken by another - // thread and need to redo the calculation. Spurious failure by weak can be ignored, because the whole allocation - // is wrapped in an infinite for loop so a failure that wasn't actually one will simply be retried until it works. - auto const updated = next.compare_exchange_weak(alloc_start, alloc_end, std::memory_order::relaxed); - if (updated) + // Current address of the free memory block now points to an address that is after our block to deallocate in heap + // memory space. + if (reinterpret_cast(current) >= end_address) { - return reinterpret_cast(alloc_start); + break; } + + previous = current; + current = current->next; } + + coalesce_free_memory_block(previous, current, header_pointer, total_size); + mutex.unlock(); } - auto user_heap_allocator::deallocate(void * pointer) noexcept -> void + auto user_heap_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) + -> void * { - if (pointer) + return replace_free_memory_block(previous_block, current_block, current_block->next); + } + + auto user_heap_allocator::split_free_memory_block(memory_block * previous_block, memory_block * current_block, + std::size_t size) -> void * + { + auto const end_address = reinterpret_cast(current_block) + size; + auto const new_block = + new (reinterpret_cast(end_address)) memory_block(current_block->size - size, current_block->next); + return replace_free_memory_block(previous_block, current_block, new_block); + } + + auto user_heap_allocator::replace_free_memory_block(memory_block * previous_block, memory_block * current_block, + memory_block * new_block) -> void * + { + auto const start_address = reinterpret_cast(current_block); + // If we want to allocate into the first block that is before any other free block, then there exists no previous + // free block (nullptr). Therefore we have to overwrite the first block instead of overwriting its next value. + if (previous_block == nullptr) + { + first = new_block; + } + else + { + previous_block->next = new_block; + } + current_block->~memory_block(); + return reinterpret_cast(start_address); + } + + auto user_heap_allocator::coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, + void * pointer, std::size_t size) -> void + { + auto const start_address = reinterpret_cast(pointer); + auto const end_address = start_address + size; + + // Inital values if there are no adjacent blocks either before or after, meaning we have to simply create a free + // memory block that is placed in between the previous and next block. + auto block_size = size; + auto next_block = current_block; + + // If the block we want to deallocate is before another free block and we can therefore combine both into one. + // This is done by deleting the current free block and creating a new block at the start address of the block to + // deallocate with both the size of the block to deallcoate and the free block next to it. + if (end_address == reinterpret_cast(current_block)) + { + block_size += current_block->size; + next_block = current_block->next; + current_block->~memory_block(); + } + + // If the block we want to deallocate is behind another free block and we can therefore combine both into one. + // This is done by simply changin the size of the previous block to include the size of the block to deallocate. + // This is done, because the previous block might still be referencered by the next field of other memory blocks. + if (previous_block != nullptr && + start_address == (reinterpret_cast(previous_block) + previous_block->size)) + { + block_size += previous_block->size; + + previous_block->size = block_size; + previous_block->next = next_block; + return; + } + + // Check if the block we want to deallocate is contained in the previous block, because if it is it can only mean + // that the block has already been deallocated and we therefore attempted a double free. + exception_handling::assert(previous_block == nullptr || + start_address >= + (reinterpret_cast(previous_block) + previous_block->size), + "[Linked List Allocator] Attempted double free detected"); + + auto const new_block = new (pointer) memory_block(block_size, next_block); + // If we want to deallocate the first block that is before any other free block, then there exists no previous free + // block (nullptr). Therefore we have to overwrite the first block instead of overwriting its + // next value. + if (previous_block == nullptr) { + first = new_block; + return; } + previous_block->next = new_block; } } // namespace teachos::arch::memory::heap -- cgit v1.2.3 From f3a976be198d97573b630242c0f833c290c62d81 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 10 May 2025 10:33:26 +0000 Subject: experiment with globally available linker sections and page table entry flags --- arch/x86_64/src/memory/paging/page_entry.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index c76c673..57e33f7 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -39,6 +39,8 @@ namespace teachos::arch::memory::paging auto entry::set_user_accesible() -> void { flags |= entry::USER_ACCESSIBLE; } + auto entry::set_global() -> void { flags |= entry::GLOBAL; } + auto entry::calculate_pointed_to_frame() const -> std::optional { if (contains_flags(PRESENT)) -- cgit v1.2.3 From 955ab48fe6329b2cbc8c5855a8ba7290185d0ea3 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 11 May 2025 07:20:54 +0000 Subject: rename page table entry function --- arch/x86_64/src/memory/paging/page_entry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 57e33f7..a5b44fa 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -37,7 +37,7 @@ namespace teachos::arch::memory::paging auto entry::set_unused() -> void { flags = 0U; } - auto entry::set_user_accesible() -> void { flags |= entry::USER_ACCESSIBLE; } + auto entry::set_user_accessible() -> void { flags |= entry::USER_ACCESSIBLE; } auto entry::set_global() -> void { flags |= entry::GLOBAL; } -- cgit v1.2.3 From 833cd6446d9981a262959749c0e248e33b54c174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 11 May 2025 08:48:57 +0000 Subject: Adjust user heap allocator with expanding heap functionality --- arch/x86_64/src/context_switching/syscall/main.cpp | 17 ++++++--- .../context_switching/syscall/syscall_handler.cpp | 17 +++++++++ .../x86_64/src/memory/heap/user_heap_allocator.cpp | 41 +++++++++++++++++++++- 3 files changed, 70 insertions(+), 5 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp index 93fc613..996d7fb 100644 --- a/arch/x86_64/src/context_switching/syscall/main.cpp +++ b/arch/x86_64/src/context_switching/syscall/main.cpp @@ -2,7 +2,7 @@ namespace teachos::arch::context_switching::syscall { - auto syscall(type syscall_number, arguments args) -> error + auto syscall(type syscall_number, arguments args) -> response { asm volatile("mov %[input], %%rax" : /* no output from call */ @@ -18,9 +18,18 @@ namespace teachos::arch::context_switching::syscall asm volatile("syscall"); - error error{}; - asm volatile("mov %%rax, %[output]" : [output] "=m"(error)); - return error; + error error_code{}; + asm volatile("mov %%rax, %[output]" : [output] "=m"(error_code)); + + arguments values{}; + asm volatile("mov %%rdi, %[output]" : [output] "=m"(values.arg_0)); + asm volatile("mov %%rsi, %[output]" : [output] "=m"(values.arg_1)); + asm volatile("mov %%rdx, %[output]" : [output] "=m"(values.arg_2)); + asm volatile("mov %%r10, %[output]" : [output] "=m"(values.arg_3)); + asm volatile("mov %%r8, %[output]" : [output] "=m"(values.arg_4)); + asm volatile("mov %%r9, %[output]" : [output] "=m"(values.arg_5)); + + return {error_code, values}; } } // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index da9eb1b..b88f273 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -16,6 +16,20 @@ namespace teachos::arch::context_switching::syscall video::vga::text::newline(); return error::OK; } + + auto expand_user_heap() -> error + { + arguments args{}; + asm volatile("mov %[input], %%rdi" + : /* no output from call */ + : [input] "m"(args.arg_0) + : "memory"); + asm volatile("mov %[input], %%rsi" + : /* no output from call */ + : [input] "m"(args.arg_1) + : "memory"); + return error::OUT_OF_MEMORY; + } } // namespace auto syscall_handler() -> void @@ -46,6 +60,9 @@ namespace teachos::arch::context_switching::syscall case type::WRITE: result = write_to_vga_buffer(arg_0); break; + case type::EXPAND_HEAP: + result = expand_user_heap(); + break; default: teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); break; diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index 6843d66..ce8b0fa 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -1,5 +1,6 @@ #include "arch/memory/heap/user_heap_allocator.hpp" +#include "arch/context_switching/syscall/main.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/exception_handling/panic.hpp" @@ -18,7 +19,7 @@ namespace teachos::arch::memory::heap heap_size > min_allocatable_size(), "[Linked List Allocator] Total heap size can not be smaller than minimum of 16 bytes to hold " "atleast one memory hole entry"); - first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); + // first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); } auto user_heap_allocator::allocate(std::size_t size) -> void * @@ -57,6 +58,30 @@ namespace teachos::arch::memory::heap current = current->next; } + current = expand_heap_if_full(); + + if (current != nullptr) + { + if (current->size == total_size) + { + auto const memory_address = remove_free_memory_block(previous, current); + new (memory_address) std::size_t(total_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + else if (current->size >= total_size + min_allocatable_size()) + { + // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards + // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if + // the total size was less and simply deallocate it as well + auto const max_size = std::max(total_size, min_allocatable_size()); + auto const memory_address = split_free_memory_block(previous, current, max_size); + new (memory_address) std::size_t(max_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + } + exception_handling::panic("[Linked List Allocator] Out of memory"); } @@ -91,6 +116,20 @@ namespace teachos::arch::memory::heap mutex.unlock(); } + auto user_heap_allocator::expand_heap_if_full() -> memory_block * + { + context_switching::syscall::arguments args{}; + auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP, args); + + if (!result.error_code) + { + uint64_t const heap_start = result.values.arg_0; + uint64_t const heap_size = result.values.arg_1; + return new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); + } + return nullptr; + } + auto user_heap_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) -> void * { -- cgit v1.2.3 From ef156dd6430855434b54275b22cd43ee3cedcfdc Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 11 May 2025 09:29:56 +0000 Subject: make frame_allocator and active_page_table statically available --- .../context_switching/syscall/syscall_handler.cpp | 6 +++ arch/x86_64/src/memory/heap/memory_block.cpp | 1 + arch/x86_64/src/memory/main.cpp | 59 +++++++++++++--------- 3 files changed, 43 insertions(+), 23 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index b88f273..9ca03d9 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -2,6 +2,8 @@ #include "arch/context_switching/syscall/main.hpp" #include "arch/exception_handling/panic.hpp" +#include "arch/memory/heap/global_heap_allocator.hpp" +#include "arch/memory/main.hpp" #include "arch/video/vga/text.hpp" namespace teachos::arch::context_switching::syscall @@ -19,6 +21,10 @@ namespace teachos::arch::context_switching::syscall auto expand_user_heap() -> error { + // TODO: use actual addresses instead of this constant! + memory::remap_heap(memory::heap::USER_HEAP_SIZE + memory::heap::USER_HEAP_SIZE, memory::heap::USER_HEAP_SIZE, + memory::paging::entry::USER_ACCESSIBLE); + arguments args{}; asm volatile("mov %[input], %%rdi" : /* no output from call */ diff --git a/arch/x86_64/src/memory/heap/memory_block.cpp b/arch/x86_64/src/memory/heap/memory_block.cpp index 446cd96..9f1fea8 100644 --- a/arch/x86_64/src/memory/heap/memory_block.cpp +++ b/arch/x86_64/src/memory/heap/memory_block.cpp @@ -6,6 +6,7 @@ namespace teachos::arch::memory::heap { memory_block::memory_block(std::size_t size, memory_block * next) { + // TODO: Figure out why this memset fails memset(static_cast(this), 0, size); this->size = size; this->next = next; diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 4cdfa80..595cb0d 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -9,37 +9,47 @@ #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" +#include + namespace teachos::arch::memory { namespace { - template - auto create_frame_allocator(multiboot::memory_information const & memory_information) -> T + static std::optional frame_allocator; + + auto create_frame_allocator(multiboot::memory_information const & memory_information) + -> allocator::area_frame_allocator { - return allocator::area_frame_allocator{memory_information}; + frame_allocator.emplace(memory_information); + return frame_allocator.value(); } - template - auto remap_heap(T & allocator, paging::active_page_table & active_table, bool is_user_heap = false) -> void + auto get_frame_allocator() -> allocator::area_frame_allocator { - auto const heap_start = is_user_heap ? heap::USER_HEAP_START : heap::KERNEL_HEAP_START; - auto const heap_size = is_user_heap ? heap::USER_HEAP_SIZE : heap::KERNEL_HEAP_SIZE; + exception_handling::assert(frame_allocator.has_value(), "[Memory main] Frame allocator has not been created yet"); + return frame_allocator.value(); + } + } // namespace + + auto remap_heap(std::size_t heap_start, std::size_t heap_size, paging::entry::bitset additional_flags = {}) -> void + { + auto allocator = get_frame_allocator(); + decltype(auto) active_table = paging::active_page_table::create_or_get(); + auto const start_page = paging::virtual_page::containing_address(heap_start); + auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); - auto const start_page = paging::virtual_page::containing_address(heap_start); - auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); - paging::page_container::iterator const begin{start_page}; - paging::page_container::iterator const end{end_page}; - paging::page_container const pages{begin, end}; + paging::page_container::iterator const begin{start_page}; + paging::page_container::iterator const end{end_page}; + paging::page_container const pages{begin, end}; - constexpr auto base_flags = paging::entry::WRITABLE; - auto const flags = is_user_heap ? base_flags | paging::entry::USER_ACCESSIBLE : base_flags; + constexpr auto base_flags = paging::entry::WRITABLE; + auto const flags = base_flags | additional_flags; - for (auto const & page : pages) - { - active_table.map_page_to_next_free_frame(allocator, page, flags); - } + for (auto const & page : pages) + { + active_table.map_page_to_next_free_frame(allocator, page, flags); } - } // namespace + } auto initialize_memory_management() -> void { @@ -49,18 +59,21 @@ namespace teachos::arch::memory has_been_called = true; auto const memory_information = multiboot::read_multiboot2(); - auto allocator = create_frame_allocator(memory_information); + auto allocator = create_frame_allocator(memory_information); kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); paging::kernel_mapper kernel(allocator, memory_information); - auto & active_table = kernel.remap_kernel(); + kernel.remap_kernel(); video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); - remap_heap(allocator, active_table); // Remap kernel heap - remap_heap(allocator, active_table, true); // Remap user heap + // Remap kernel heap + remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); + // Remap user heap + remap_heap(heap::USER_HEAP_SIZE, heap::USER_HEAP_SIZE, paging::entry::USER_ACCESSIBLE); + video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); } -- cgit v1.2.3 From ee4c61f7313fedd23d01c69ea5036fa38ef6248a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 12 May 2025 08:50:12 +0000 Subject: Adjust user heap to lazy allocate heap --- .../src/context_switching/syscall/syscall_handler.cpp | 10 +++++----- arch/x86_64/src/memory/heap/global_heap_allocator.cpp | 2 +- arch/x86_64/src/memory/heap/linked_list_allocator.cpp | 4 +--- arch/x86_64/src/memory/heap/memory_block.cpp | 4 ++-- arch/x86_64/src/memory/heap/user_heap_allocator.cpp | 14 -------------- arch/x86_64/src/memory/main.cpp | 4 ---- 6 files changed, 9 insertions(+), 29 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index 9ca03d9..7272e9e 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -21,11 +21,10 @@ namespace teachos::arch::context_switching::syscall auto expand_user_heap() -> error { - // TODO: use actual addresses instead of this constant! - memory::remap_heap(memory::heap::USER_HEAP_SIZE + memory::heap::USER_HEAP_SIZE, memory::heap::USER_HEAP_SIZE, - memory::paging::entry::USER_ACCESSIBLE); + static auto current_heap_end = memory::heap::USER_HEAP_START; + memory::remap_heap(current_heap_end, memory::heap::USER_HEAP_SIZE, memory::paging::entry::USER_ACCESSIBLE); - arguments args{}; + arguments args{current_heap_end, memory::heap::USER_HEAP_SIZE}; asm volatile("mov %[input], %%rdi" : /* no output from call */ : [input] "m"(args.arg_0) @@ -34,7 +33,8 @@ namespace teachos::arch::context_switching::syscall : /* no output from call */ : [input] "m"(args.arg_1) : "memory"); - return error::OUT_OF_MEMORY; + current_heap_end += memory::heap::USER_HEAP_SIZE; + return error::OK; } } // namespace diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index 23e2458..e6c268a 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -41,7 +41,7 @@ namespace teachos::arch::memory::heap } [[gnu::section(".user_data")]] - static user_heap_allocator user_allocator{USER_HEAP_START, USER_HEAP_START + USER_HEAP_SIZE}; + static user_heap_allocator user_allocator{}; user_allocator_instance = &user_allocator; } diff --git a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp index 5101ab2..63a6111 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -8,9 +8,7 @@ namespace teachos::arch::memory::heap { linked_list_allocator::linked_list_allocator(std::size_t heap_start, std::size_t heap_end) - : heap_start(heap_start) - , heap_end(heap_end) - , first(nullptr) + : first(nullptr) , mutex{stl::mutex{}} { auto const heap_size = heap_end - heap_start; diff --git a/arch/x86_64/src/memory/heap/memory_block.cpp b/arch/x86_64/src/memory/heap/memory_block.cpp index 9f1fea8..6ee675a 100644 --- a/arch/x86_64/src/memory/heap/memory_block.cpp +++ b/arch/x86_64/src/memory/heap/memory_block.cpp @@ -7,10 +7,10 @@ namespace teachos::arch::memory::heap memory_block::memory_block(std::size_t size, memory_block * next) { // TODO: Figure out why this memset fails - memset(static_cast(this), 0, size); + // memset(static_cast(this), 0, size); this->size = size; this->next = next; } - memory_block::~memory_block() { memset(static_cast(this), 0, sizeof(memory_block)); } + memory_block::~memory_block() { /*memset(static_cast(this), 0, sizeof(memory_block));*/ } } // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index ce8b0fa..9cb6c17 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -8,20 +8,6 @@ namespace teachos::arch::memory::heap { - user_heap_allocator::user_heap_allocator(std::size_t heap_start, std::size_t heap_end) - : heap_start(heap_start) - , heap_end(heap_end) - , first(nullptr) - , mutex{stl::mutex{}} - { - auto const heap_size = heap_end - heap_start; - exception_handling::assert( - heap_size > min_allocatable_size(), - "[Linked List Allocator] Total heap size can not be smaller than minimum of 16 bytes to hold " - "atleast one memory hole entry"); - // first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); - } - auto user_heap_allocator::allocate(std::size_t size) -> void * { // Add size of size_t to the total allocated size, because we add a header that includes the size of the allocated diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 595cb0d..5e671ac 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -69,11 +69,7 @@ namespace teachos::arch::memory video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); - // Remap kernel heap remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); - // Remap user heap - remap_heap(heap::USER_HEAP_SIZE, heap::USER_HEAP_SIZE, paging::entry::USER_ACCESSIBLE); - video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); } -- cgit v1.2.3 From 29e067867e7a437d12351b481024d4bab431b202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 12 May 2025 13:51:12 +0000 Subject: Fix crashes because of are frame allocator copy --- arch/x86_64/src/context_switching/syscall/main.cpp | 6 +-- .../context_switching/syscall/syscall_handler.cpp | 50 ++++++++++++++-------- arch/x86_64/src/memory/heap/memory_block.cpp | 5 +-- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 13 ++---- arch/x86_64/src/memory/main.cpp | 11 ++--- 5 files changed, 48 insertions(+), 37 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp index 996d7fb..e291c10 100644 --- a/arch/x86_64/src/context_switching/syscall/main.cpp +++ b/arch/x86_64/src/context_switching/syscall/main.cpp @@ -18,9 +18,6 @@ namespace teachos::arch::context_switching::syscall asm volatile("syscall"); - error error_code{}; - asm volatile("mov %%rax, %[output]" : [output] "=m"(error_code)); - arguments values{}; asm volatile("mov %%rdi, %[output]" : [output] "=m"(values.arg_0)); asm volatile("mov %%rsi, %[output]" : [output] "=m"(values.arg_1)); @@ -29,6 +26,9 @@ namespace teachos::arch::context_switching::syscall asm volatile("mov %%r8, %[output]" : [output] "=m"(values.arg_4)); asm volatile("mov %%r9, %[output]" : [output] "=m"(values.arg_5)); + error error_code{}; + asm volatile("mov %%rax, %[output]" : [output] "=m"(error_code)); + return {error_code, values}; } diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index 7272e9e..9cc6edf 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -11,30 +11,21 @@ namespace teachos::arch::context_switching::syscall namespace { - auto write_to_vga_buffer(uint64_t buffer) -> error + auto write_to_vga_buffer(uint64_t buffer) -> response { video::vga::text::write(reinterpret_cast(buffer), video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); - return error::OK; + return {error::OK}; } - auto expand_user_heap() -> error + auto expand_user_heap() -> response { static auto current_heap_end = memory::heap::USER_HEAP_START; - memory::remap_heap(current_heap_end, memory::heap::USER_HEAP_SIZE, memory::paging::entry::USER_ACCESSIBLE); - - arguments args{current_heap_end, memory::heap::USER_HEAP_SIZE}; - asm volatile("mov %[input], %%rdi" - : /* no output from call */ - : [input] "m"(args.arg_0) - : "memory"); - asm volatile("mov %[input], %%rsi" - : /* no output from call */ - : [input] "m"(args.arg_1) - : "memory"); + uint64_t const heap_start = current_heap_end; + memory::remap_heap(heap_start, memory::heap::USER_HEAP_SIZE, memory::paging::entry::USER_ACCESSIBLE); current_heap_end += memory::heap::USER_HEAP_SIZE; - return error::OK; + return {error::OK, {heap_start, memory::heap::USER_HEAP_SIZE}}; } } // namespace @@ -60,7 +51,7 @@ namespace teachos::arch::context_switching::syscall // and now. asm volatile("mov %%rax, %[output]" : [output] "=m"(syscall_number)); - error result = error::OK; + response result; switch (static_cast(syscall_number)) { case type::WRITE: @@ -76,7 +67,32 @@ namespace teachos::arch::context_switching::syscall asm volatile("mov %[input], %%rax" : /* no output from call */ - : [input] "m"(result) + : [input] "m"(result.error_code) + : "memory"); + + asm volatile("mov %[input], %%rdi" + : /* no output from call */ + : [input] "m"(result.values.arg_0) + : "memory"); + asm volatile("mov %[input], %%rsi" + : /* no output from call */ + : [input] "m"(result.values.arg_1) + : "memory"); + asm volatile("mov %[input], %%rdx" + : /* no output from call */ + : [input] "m"(result.values.arg_2) + : "memory"); + asm volatile("mov %[input], %%r10" + : /* no output from call */ + : [input] "m"(result.values.arg_3) + : "memory"); + asm volatile("mov %[input], %%r8" + : /* no output from call */ + : [input] "m"(result.values.arg_4) + : "memory"); + asm volatile("mov %[input], %%r9" + : /* no output from call */ + : [input] "m"(result.values.arg_5) : "memory"); asm volatile("mov %[input], %%rcx" diff --git a/arch/x86_64/src/memory/heap/memory_block.cpp b/arch/x86_64/src/memory/heap/memory_block.cpp index 6ee675a..bc97bd6 100644 --- a/arch/x86_64/src/memory/heap/memory_block.cpp +++ b/arch/x86_64/src/memory/heap/memory_block.cpp @@ -6,11 +6,10 @@ namespace teachos::arch::memory::heap { memory_block::memory_block(std::size_t size, memory_block * next) { - // TODO: Figure out why this memset fails - // memset(static_cast(this), 0, size); + memset(static_cast(this), 0U, size); this->size = size; this->next = next; } - memory_block::~memory_block() { /*memset(static_cast(this), 0, sizeof(memory_block));*/ } + memory_block::~memory_block() { memset(static_cast(this), 0U, sizeof(memory_block)); } } // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index 9cb6c17..f3fe1c2 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -104,16 +104,11 @@ namespace teachos::arch::memory::heap auto user_heap_allocator::expand_heap_if_full() -> memory_block * { - context_switching::syscall::arguments args{}; - auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP, args); + auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP); - if (!result.error_code) - { - uint64_t const heap_start = result.values.arg_0; - uint64_t const heap_size = result.values.arg_1; - return new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); - } - return nullptr; + uint64_t const heap_start = result.values.arg_0; + uint64_t const heap_size = result.values.arg_1; + return !result.error_code ? new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr) : nullptr; } auto user_heap_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 5e671ac..2746a71 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -18,22 +18,23 @@ namespace teachos::arch::memory static std::optional frame_allocator; auto create_frame_allocator(multiboot::memory_information const & memory_information) - -> allocator::area_frame_allocator + -> allocator::area_frame_allocator & { frame_allocator.emplace(memory_information); return frame_allocator.value(); } - auto get_frame_allocator() -> allocator::area_frame_allocator + auto get_frame_allocator() -> allocator::area_frame_allocator & { - exception_handling::assert(frame_allocator.has_value(), "[Memory main] Frame allocator has not been created yet"); + exception_handling::assert(frame_allocator.has_value(), + "[Initialization] Frame allocator has not been created yet"); return frame_allocator.value(); } } // namespace auto remap_heap(std::size_t heap_start, std::size_t heap_size, paging::entry::bitset additional_flags = {}) -> void { - auto allocator = get_frame_allocator(); + decltype(auto) allocator = get_frame_allocator(); decltype(auto) active_table = paging::active_page_table::create_or_get(); auto const start_page = paging::virtual_page::containing_address(heap_start); auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); @@ -59,7 +60,7 @@ namespace teachos::arch::memory has_been_called = true; auto const memory_information = multiboot::read_multiboot2(); - auto allocator = create_frame_allocator(memory_information); + decltype(auto) allocator = create_frame_allocator(memory_information); kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); -- cgit v1.2.3 From d4cc546df6eba2dd287785f1a63fbcce4a1b9bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 16 May 2025 09:58:57 +0000 Subject: Attempt to move atomic into stl text as well --- arch/x86_64/src/user/main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 59647f8..a435a41 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -3,6 +3,9 @@ #include "arch/context_switching/syscall/main.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" +#include +#include + // TODO: Disallow these imports #include "arch/kernel/cpu/if.hpp" #include "arch/video/vga/text.hpp" @@ -17,6 +20,12 @@ namespace teachos::arch::user // kernel::cpu::clear_interrupt_flag(); // Causes crash Kernel Code (.text) is not mapped in User mMde + int test = std::max(5, 10); + (void)test; + + std::atomic locked = {false}; + locked.exchange(true); + auto address = memory::heap::global_heap_allocator::malloc(8U); (void)address; -- cgit v1.2.3 From 5c314eef566df2732973e8cb35974ec49748adba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 16 May 2025 13:27:16 +0000 Subject: Fix bug where level 4 to level 2 entries are not mapped user accesible. --- arch/x86_64/src/memory/paging/page_entry.cpp | 2 -- arch/x86_64/src/user/main.cpp | 16 ---------------- 2 files changed, 18 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index a5b44fa..57045ca 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -39,8 +39,6 @@ namespace teachos::arch::memory::paging auto entry::set_user_accessible() -> void { flags |= entry::USER_ACCESSIBLE; } - auto entry::set_global() -> void { flags |= entry::GLOBAL; } - auto entry::calculate_pointed_to_frame() const -> std::optional { if (contains_flags(PRESENT)) diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index a435a41..747a8a4 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -6,10 +6,6 @@ #include #include -// TODO: Disallow these imports -#include "arch/kernel/cpu/if.hpp" -#include "arch/video/vga/text.hpp" - namespace teachos::arch::user { auto main() -> void @@ -18,8 +14,6 @@ namespace teachos::arch::user context_switching::syscall::syscall(context_switching::syscall::type::WRITE, {reinterpret_cast(&syscall_message)}); - // kernel::cpu::clear_interrupt_flag(); // Causes crash Kernel Code (.text) is not mapped in User mMde - int test = std::max(5, 10); (void)test; @@ -29,16 +23,6 @@ namespace teachos::arch::user auto address = memory::heap::global_heap_allocator::malloc(8U); (void)address; - // auto test = new int{20}; // Causes crash Heap is not mapped in User Mode - // (void)test; - - // if (!error) - // { - // // Causes crash vga is not mapped in User Mode - // video::vga::text::write("Successfully made a SYSCALL and returned with SYSRETQ!", - // video::vga::text::common_attributes::green_on_black); - // } - for (;;) { } -- cgit v1.2.3 From 1b5a771a34743a2973a82de5ebdfd22da030b841 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 18 May 2025 13:21:42 +0000 Subject: update linker file and improve section parsing --- arch/x86_64/src/user/main.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index 747a8a4..e621327 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -4,22 +4,29 @@ #include "arch/memory/heap/global_heap_allocator.hpp" #include +#include #include +#include namespace teachos::arch::user { auto main() -> void { + // Test writing to VGA Buffer char constexpr syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; context_switching::syscall::syscall(context_switching::syscall::type::WRITE, {reinterpret_cast(&syscall_message)}); - int test = std::max(5, 10); - (void)test; - - std::atomic locked = {false}; - locked.exchange(true); + // Test C++ standard library + std::array, 4> array_test = {std::atomic{5}, std::atomic{10}, + std::atomic{15}, std::atomic{20}}; + std::ranges::for_each(array_test, [](auto & item) { + auto value = item.load(); + uint8_t max_value = std::max(value, uint8_t{10}); + item.exchange(max_value + 2); + }); + // Test user heap auto address = memory::heap::global_heap_allocator::malloc(8U); (void)address; -- cgit v1.2.3 From 8d39f3f67734bf39cada370c39243e6ef33bf4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 18 May 2025 14:45:05 +0000 Subject: Make new usable for both kernel and user calls --- .../segment_selector.cpp | 2 + .../context_switching/syscall/syscall_handler.cpp | 6 ++ .../src/memory/heap/global_heap_allocator.cpp | 66 +++++++++++++++++----- arch/x86_64/src/user/main.cpp | 6 +- 4 files changed, 61 insertions(+), 19 deletions(-) (limited to 'arch/x86_64/src') 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 8568447..27f0a3b 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 @@ -7,6 +7,8 @@ namespace teachos::arch::context_switching::interrupt_descriptor_table return (std::bitset<3U>{_flags} & other) == other; } + auto segment_selector::get_index() const -> uint16_t { return _index; } + auto segment_selector::operator|=(std::bitset<3U> other) -> void { _flags |= other.to_ulong(); } segment_selector::operator uint16_t() const { return *reinterpret_cast(this); } diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index 9cc6edf..cd1c8a2 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -60,6 +60,12 @@ namespace teachos::arch::context_switching::syscall case type::EXPAND_HEAP: result = expand_user_heap(); break; + case type::ASSERT: + if (!arg_0) + { + teachos::arch::exception_handling::panic(reinterpret_cast(arg_1)); + } + break; default: teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); break; diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp index e6c268a..35cd623 100644 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp @@ -1,12 +1,29 @@ #include "arch/memory/heap/global_heap_allocator.hpp" +#include "arch/context_switching/syscall/main.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/kernel/cpu/segment_register.hpp" #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/linked_list_allocator.hpp" #include "arch/memory/heap/user_heap_allocator.hpp" namespace teachos::arch::memory::heap { + namespace + { + constexpr char NOT_REGISTRED_ERROR_MESSAGE[] = + "Attempted to allocate or deallocate using the global_heap_allocator before " + "register_heap_allocation_type was called."; + constexpr uint16_t KERNEL_CODE_INDEX = 1U; + + [[gnu::section(".user_text")]] + auto os_in_kernel_mode() -> bool + { + auto const cs = teachos::arch::kernel::cpu::read_code_segment_register(); + return cs.get_index() == KERNEL_CODE_INDEX; + } + } // namespace + heap_allocator * global_heap_allocator::kernel_allocator_instance = nullptr; user_heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; @@ -47,53 +64,72 @@ namespace teachos::arch::memory::heap auto global_heap_allocator::kernel() -> heap_allocator & { - exception_handling::assert(kernel_allocator_instance != nullptr, - "Attempted to allocate or deallocate using the global_heap_allocator before " - "register_heap_allocation_type was called."); + exception_handling::assert(kernel_allocator_instance != nullptr, NOT_REGISTRED_ERROR_MESSAGE); return *kernel_allocator_instance; } auto global_heap_allocator::user() -> user_heap_allocator & { - // TODO: Assert Method does not exist in .user_text meaning this causes a Page Fault when accessed, Make it into a - // syscall instead - // exception_handling::assert(user_allocator_instance != nullptr, - // "Attempted to allocate or deallocate using the global_heap_allocator before " - // "register_heap_allocation_type was called."); - + context_switching::syscall::syscall( + context_switching::syscall::type::ASSERT, + {user_allocator_instance != nullptr, reinterpret_cast(&NOT_REGISTRED_ERROR_MESSAGE)}); return *user_allocator_instance; } } // namespace teachos::arch::memory::heap auto operator new(std::size_t size) -> void * { - return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + } + return teachos::arch::memory::heap::global_heap_allocator::malloc(size); } auto operator delete(void * pointer) noexcept -> void { - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); } auto operator delete(void * pointer, std::size_t size) noexcept -> void { (void)size; - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); } auto operator new[](std::size_t size) -> void * { - return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); + } + return teachos::arch::memory::heap::global_heap_allocator::malloc(size); } auto operator delete[](void * pointer) noexcept -> void { - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); } auto operator delete[](void * pointer, std::size_t size) noexcept -> void { (void)size; - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + if (teachos::arch::memory::heap::os_in_kernel_mode()) + { + teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); + } + teachos::arch::memory::heap::global_heap_allocator::free(pointer); } diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp index e621327..8b07e4a 100644 --- a/arch/x86_64/src/user/main.cpp +++ b/arch/x86_64/src/user/main.cpp @@ -12,8 +12,7 @@ namespace teachos::arch::user { auto main() -> void { - // Test writing to VGA Buffer - char constexpr syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; + constexpr char syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; context_switching::syscall::syscall(context_switching::syscall::type::WRITE, {reinterpret_cast(&syscall_message)}); @@ -26,8 +25,7 @@ namespace teachos::arch::user item.exchange(max_value + 2); }); - // Test user heap - auto address = memory::heap::global_heap_allocator::malloc(8U); + auto address = new uint64_t{10U}; (void)address; for (;;) -- cgit v1.2.3 From 8a6a9a3a159ce1b960721eb921b8e8d81b15b718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 20 May 2025 12:29:09 +0000 Subject: Improve syscalls and user heap allocator --- .../context_switching/syscall/syscall_handler.cpp | 6 +- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 80 +++++++++++----------- 2 files changed, 42 insertions(+), 44 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index cd1c8a2..af6d911 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -1,6 +1,7 @@ #include "arch/context_switching/syscall/syscall_handler.hpp" #include "arch/context_switching/syscall/main.hpp" +#include "arch/exception_handling/assert.hpp" #include "arch/exception_handling/panic.hpp" #include "arch/memory/heap/global_heap_allocator.hpp" #include "arch/memory/main.hpp" @@ -61,10 +62,7 @@ namespace teachos::arch::context_switching::syscall result = expand_user_heap(); break; case type::ASSERT: - if (!arg_0) - { - teachos::arch::exception_handling::panic(reinterpret_cast(arg_1)); - } + teachos::arch::exception_handling::assert(arg_0, reinterpret_cast(arg_1)); break; default: teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp index f3fe1c2..427a68a 100644 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp @@ -1,8 +1,6 @@ #include "arch/memory/heap/user_heap_allocator.hpp" #include "arch/context_switching/syscall/main.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/exception_handling/panic.hpp" #include @@ -20,24 +18,10 @@ namespace teachos::arch::memory::heap while (current != nullptr) { - // TODO: Can not access current pointer. Results in a General Protection Fault? - if (current->size == total_size) + auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size); + if (memory.has_value()) { - auto const memory_address = remove_free_memory_block(previous, current); - new (memory_address) std::size_t(total_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); - } - else if (current->size >= total_size + min_allocatable_size()) - { - // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards - // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if - // the total size was less and simply deallocate it as well - auto const max_size = std::max(total_size, min_allocatable_size()); - auto const memory_address = split_free_memory_block(previous, current, max_size); - new (memory_address) std::size_t(max_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + return memory.value(); } previous = current; @@ -48,27 +32,17 @@ namespace teachos::arch::memory::heap if (current != nullptr) { - if (current->size == total_size) - { - auto const memory_address = remove_free_memory_block(previous, current); - new (memory_address) std::size_t(total_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); - } - else if (current->size >= total_size + min_allocatable_size()) + auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size); + if (memory.has_value()) { - // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards - // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if - // the total size was less and simply deallocate it as well - auto const max_size = std::max(total_size, min_allocatable_size()); - auto const memory_address = split_free_memory_block(previous, current, max_size); - new (memory_address) std::size_t(max_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + return memory.value(); } } - exception_handling::panic("[Linked List Allocator] Out of memory"); + char constexpr OUT_OF_MEMORY_ERROR_MESSAGE[] = "[Linked List Allocator] Out of memory"; + context_switching::syscall::syscall(context_switching::syscall::type::ASSERT, + {false, reinterpret_cast(&OUT_OF_MEMORY_ERROR_MESSAGE)}); + return nullptr; } auto user_heap_allocator::deallocate(void * pointer) noexcept -> void @@ -102,6 +76,30 @@ namespace teachos::arch::memory::heap mutex.unlock(); } + auto user_heap_allocator::allocate_into_memory_block_if_big_enough(memory_block * current, memory_block * previous, + std::size_t total_size) -> std::optional + { + if (current->size == total_size) + { + auto const memory_address = remove_free_memory_block(previous, current); + new (memory_address) std::size_t(total_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + else if (current->size >= total_size + min_allocatable_size()) + { + // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards + // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if + // the total size was less and simply deallocate it as well + auto const max_size = std::max(total_size, min_allocatable_size()); + auto const memory_address = split_free_memory_block(previous, current, max_size); + new (memory_address) std::size_t(max_size); + mutex.unlock(); + return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); + } + return std::nullopt; + } + auto user_heap_allocator::expand_heap_if_full() -> memory_block * { auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP); @@ -180,10 +178,12 @@ namespace teachos::arch::memory::heap // Check if the block we want to deallocate is contained in the previous block, because if it is it can only mean // that the block has already been deallocated and we therefore attempted a double free. - exception_handling::assert(previous_block == nullptr || - start_address >= - (reinterpret_cast(previous_block) + previous_block->size), - "[Linked List Allocator] Attempted double free detected"); + char constexpr DOUBLE_FREE_ERROR_MESSAGE[] = "[Linked List Allocator] Attempted double free detected"; + context_switching::syscall::syscall( + context_switching::syscall::type::ASSERT, + {previous_block == nullptr || + start_address >= (reinterpret_cast(previous_block) + previous_block->size), + reinterpret_cast(&DOUBLE_FREE_ERROR_MESSAGE)}); auto const new_block = new (pointer) memory_block(block_size, next_block); // If we want to deallocate the first block that is before any other free block, then there exists no previous free -- cgit v1.2.3 From 3e597ede8079883b3b9d48faf94b8a7bec2a2118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 27 May 2025 12:41:50 +0000 Subject: Readd text kernels ection with explanation --- arch/x86_64/src/context_switching/syscall/syscall_handler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp index af6d911..84dbe5f 100644 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp @@ -108,9 +108,9 @@ namespace teachos::arch::context_switching::syscall : [input] "m"(rflags) : "memory"); - // Additionally call leave, because x86 allocates tack space for the internal variables. If we do not clean up this + // Additionally call leave, because x86 allocates stack space for the internal variables. If we do not clean up this // newly created stack frame the syscall instruction that landed in this syscall_handler, will never return to the - // method that originally called it, becuase the RIP has not been restored from the previous stack frame. + // method that originally called it, because the RIP has not been restored from the previous stack frame. asm volatile("leave\n" "sysretq"); } -- cgit v1.2.3 From 9f2e780030e2101d5f7f01f42df805db9a5fa809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 30 May 2025 12:48:57 +0000 Subject: Clean up files --- .../src/memory/allocator/stack_frame_allocator.cpp | 105 --------------------- 1 file changed, 105 deletions(-) delete mode 100644 arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp deleted file mode 100644 index 0fa277a..0000000 --- a/arch/x86_64/src/memory/allocator/stack_frame_allocator.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "arch/memory/allocator/stack_frame_allocator.hpp" - -#include "arch/exception_handling/assert.hpp" - -#include -#include -#include - -namespace teachos::arch::memory::allocator -{ - stack_frame_allocator::stack_frame_allocator(multiboot::memory_information const & mem_info) - : free_frames() - , next_free_frame() - , current_area(std::nullopt) - , memory_areas(mem_info.areas) - , kernel_start(physical_frame::containing_address(mem_info.kernel_start)) - , kernel_end(physical_frame::containing_address(mem_info.kernel_end)) - , multiboot_start(physical_frame::containing_address(mem_info.multiboot_start)) - , multiboot_end(physical_frame::containing_address(mem_info.multiboot_end)) - { - load_free_physical_frames(); - } - - auto stack_frame_allocator::load_free_physical_frames() -> void - { - choose_next_area(); - if (!current_area.has_value()) - { - return; - } - - auto const address = current_area.value().base_address + current_area.value().area_length - 1; - physical_frame const current_area_last_frame = physical_frame::containing_address(address); - - // Only try to allocate memory if current_area is not null, because - // the current_area is null if there is no more available memory. - while (next_free_frame <= current_area_last_frame) - { - if (next_free_frame >= kernel_start && next_free_frame <= kernel_end) - { - // `physical_frame` is used by the kernel or multiboot information structure. - next_free_frame = allocator::physical_frame{kernel_end.frame_number + 1}; - } - else if (next_free_frame >= multiboot_start && next_free_frame <= multiboot_end) - { - // `physical_frame` is used by the kernel or multiboot information structure. - next_free_frame = allocator::physical_frame{multiboot_end.frame_number + 1}; - } - else - { - // Frame is unused, increment `next_free_frame` and return it. - next_free_frame.frame_number += 1; - // TODO: Fix using heap like structure to initalize paging allocator used by heap does not work - // free_frames.push(next_free_frame); - static uint32_t count = 0U; - count++; - } - } - } - - auto stack_frame_allocator::choose_next_area() -> void - { - current_area = std::nullopt; - auto next_area_with_free_frames = memory_areas | std::views::filter([this](auto const & area) { - auto address = area.base_address + area.area_length - 1; - return physical_frame::containing_address(address) >= next_free_frame; - }); - - auto const lowest_area_with_free_frames = std::ranges::min_element( - next_area_with_free_frames, [](auto const & a, auto const & b) { return a.base_address < b.base_address; }); - - if (lowest_area_with_free_frames != next_area_with_free_frames.end()) - { - current_area = *lowest_area_with_free_frames; - // Update the `next_free_frame` according to the new memory area - auto const start_frame = physical_frame::containing_address(current_area.value().base_address); - if (next_free_frame < start_frame) - { - next_free_frame = start_frame; - } - } - } - - auto stack_frame_allocator::allocate_frame() -> std::optional - { - // If the underlying stack is empty that are no free frames left to allocate. - if (free_frames.empty()) - { - load_free_physical_frames(); - if (free_frames.empty()) - { - return std::nullopt; - } - } - - decltype(auto) top = free_frames.top(); - free_frames.pop(); - return top; - } - - auto stack_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void - { - free_frames.push(physical_frame); - } -} // namespace teachos::arch::memory::allocator -- cgit v1.2.3