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
|
#include "arch/memory/kernel_mapper.hpp"
#include "kapi/memory.hpp"
#include "kapi/system.hpp"
#include "arch/boot/ld.hpp"
#include <kstd/print>
#include <kstd/units>
#include <elf/format.hpp>
#include <elf/section_header.hpp>
#include <multiboot2/information.hpp>
#include <algorithm>
#include <array>
#include <bit>
#include <cstdint>
#include <ranges>
#include <string_view>
#include <utility>
using namespace std::string_view_literals;
using namespace kstd::units_literals;
namespace arch::memory
{
namespace
{
constexpr auto static ignored_section_prefixes = std::array{
".boot_"sv,
};
constexpr auto static user_accessible_prefixes = std::array{
".user"sv,
".stl"sv,
};
} // namespace
kernel_mapper::kernel_mapper(multiboot2::information_view const * mbi)
: m_mbi{std::move(mbi)}
, m_kernel_load_base{std::bit_cast<std::uintptr_t>(&arch::boot::TEACHOS_VMA)}
{}
auto kernel_mapper::remap_kernel(kapi::memory::page_mapper & mapper) -> void
{
auto elf_information = m_mbi->maybe_elf_symbols<elf::format::elf64>();
if (!elf_information)
{
kapi::system::panic("[x86_64:MEM] ELF section information is not available.");
}
auto sections = *elf_information;
auto allocated_sections =
std::views::all(sections) | std::views::filter(&elf::section_header<elf::format::elf64>::allocated) |
std::views::filter([&](auto const & section) -> auto {
auto name = sections.name(section);
return !std::ranges::any_of(ignored_section_prefixes,
[&](auto const & prefix) -> auto { return name.starts_with(prefix); });
});
if (allocated_sections.empty())
{
kapi::system::panic("[x86_64:MEM] No allocated ELF sections were found.");
}
std::ranges::for_each(allocated_sections,
[&](auto const & section) -> auto { map_section(section, sections.name(section), mapper); });
}
auto kernel_mapper::map_section(section_header_type const & section, std::string_view name,
kapi::memory::page_mapper & mapper) -> void
{
auto number_of_pages =
(kstd::units::bytes{section.size} + (kapi::memory::page::size - 1_B)) / kapi::memory::page::size;
auto linear_start_address = kapi::memory::linear_address{section.virtual_load_address};
auto physical_start_address = kapi::memory::physical_address{section.virtual_load_address & ~m_kernel_load_base};
kstd::println("[x86_64:MEM] mapping {}"
"\n {} bytes -> page count: {}"
"\n {} @ {}",
name, section.size, number_of_pages, linear_start_address, physical_start_address);
auto first_page = kapi::memory::page::containing(linear_start_address);
auto first_frame = kapi::memory::frame::containing(physical_start_address);
auto page_flags = kapi::memory::page_mapper::flags::empty;
if (section.writable())
{
page_flags |= kapi::memory::page_mapper::flags::writable;
}
if (section.executable())
{
page_flags |= kapi::memory::page_mapper::flags::executable;
}
auto is_prefix_of_name = [=](auto prefix) -> bool {
return name.starts_with(prefix);
};
if (!std::ranges::any_of(user_accessible_prefixes, is_prefix_of_name))
{
page_flags |= kapi::memory::page_mapper::flags::supervisor_only;
}
for (auto i = 0uz; i < number_of_pages; ++i)
{
mapper.map(first_page + i, first_frame + i, page_flags);
}
}
} // namespace arch::memory
|