1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
#include "kapi/memory.hpp"
#include "kapi/cio.hpp"
#include "kapi/system.hpp"
#include "x86_64/boot/boot.hpp"
#include "x86_64/boot/ld.hpp"
#include "x86_64/cpu/registers.hpp"
#include "x86_64/memory/mmu.hpp"
#include "x86_64/memory/page_table.hpp"
#include "x86_64/memory/paging_root.hpp"
#include "x86_64/memory/region_allocator.hpp"
#include <multiboot2/information.hpp>
#include <atomic>
#include <memory>
#include <span>
namespace teachos::memory
{
std::size_t const PLATFORM_FRAME_SIZE{4096};
std::size_t const PLATFORM_PAGE_SIZE{PLATFORM_FRAME_SIZE};
namespace
{
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
auto constinit allocator = static_cast<frame_allocator *>(nullptr);
constexpr auto static unused_page_address = 0x0000'7fff'cafe'faceuz;
auto create_memory_information() -> x86_64::region_allocator::memory_information
{
auto const & mbi = boot::bootstrap_information.mbi;
auto mbi_span = std::span{std::bit_cast<std::byte *>(mbi), mbi->size_bytes()};
auto image_span = std::span{&boot::x86_64::_start_physical, &boot::x86_64::_end_physical};
return {.image_range =
std::make_pair(physical_address{&image_span.front()}, physical_address{&image_span.back()}),
.mbi_range = std::make_pair(physical_address{&mbi_span.front()}, physical_address{&mbi_span.back()}),
.memory_map = mbi->memory_map()};
};
auto create_early_frame_allocator()
{
auto memory_map = boot::bootstrap_information.mbi->maybe_memory_map();
if (!memory_map)
{
system::panic("[x86_64] Failed to create early allocator, no memory map available.");
}
return x86_64::region_allocator{create_memory_information()};
}
auto enable_cpu_protections() -> void
{
cpu::x86_64::cr0::set(cpu::x86_64::cr0::flags::write_protect);
cpu::x86_64::i32_efer::set(cpu::x86_64::i32_efer::flags::execute_disable_bit_enable);
}
auto inject_faux_pml4(frame_allocator & allocator) -> void
{
using entry_flags = x86_64::page_table::entry::flags;
using page_table = x86_64::page_table;
auto temporary_page = page::containing(linear_address{unused_page_address});
auto temporary_page_address = temporary_page.start_address();
auto & pml4 = x86_64::paging_root::get();
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)
auto faux_pml4_frame =
allocator.allocate()
.and_then([&](auto frame) -> auto {
auto index = temporary_page_address >> 39 & 0x1ffu;
pml4[index].frame(frame, entry_flags::present | entry_flags::writable);
return pml4.next(index);
})
.and_then([&](auto pml) -> auto {
std::construct_at(pml);
auto index = temporary_page_address >> 30 & 0x1ffu;
(*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable);
return pml->next(index);
})
.and_then([&](auto pml) -> auto {
std::construct_at(pml);
auto index = temporary_page_address >> 21 & 0x1ffu;
(*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable);
return pml->next(index);
})
.transform([&](auto pml) -> auto {
std::construct_at(pml);
auto index = temporary_page_address >> 12 & 0x1ffu;
(*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable);
return pml;
})
.and_then([&](auto pml) -> auto {
auto faux_pml4_pointer = std::bit_cast<page_table *>(temporary_page_address.raw());
auto faux_pml4 = std::construct_at<page_table>(faux_pml4_pointer);
auto index = temporary_page_address >> 12 & 0x1ffu;
auto frame = (*pml)[index].frame();
(*faux_pml4)[510].frame(*frame, entry_flags::present | entry_flags::writable);
return frame;
});
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers)
if (!faux_pml4_frame)
{
system::panic("[MEM] Failed to map and construct faux PML4");
}
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
pml4[510].frame(*faux_pml4_frame, entry_flags::present | entry_flags::writable);
x86_64::tlb_flush_all();
cio::println("[MEM] Injected faux PML4 as recursive map.");
}
} // namespace
auto active_allocator() -> frame_allocator &
{
if (!allocator)
{
system::panic("[x86_64] The frame allocator has not been set yet.");
}
return *allocator;
}
auto init() -> void
{
auto static constinit is_initialized = std::atomic_flag{};
if (is_initialized.test_and_set())
{
system::panic("[x86_64] Memory management has already been initialized.");
}
auto allocator = create_early_frame_allocator();
enable_cpu_protections();
inject_faux_pml4(allocator);
// paging::kernel_mapper kernel(allocator, memory_information);
// kernel.remap_kernel();
// video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black);
// video::vga::text::newline();
// remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE);
// video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black);
// video::vga::text::newline();
}
} // namespace teachos::memory
|