-
Notifications
You must be signed in to change notification settings - Fork 1
/
paging.hpp
219 lines (164 loc) · 6.8 KB
/
paging.hpp
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
////////////////////////////////////////////////////////////////
//
// Memory paging for x86
//
// File: paging.hpp
// Date: 16 Mar 2023
//
// Copyright (c) 2017 - 2022, Igor Baklykov
// All rights reserved.
//
//
#pragma once
// IgrOS-Kernel arch
#include <arch/types.hpp>
// IgrOS-Kernel library
#include <klib/kFlags.hpp>
// x86_64 namespace
namespace igros::x86_64 {
// Forward declaration
struct register_t;
// Paging structure
class paging final {
public:
// Page Map Level 4 max entries count
constexpr static auto PAGE_MAP_LEVEL_4_SIZE {512_usize};
// Page Directory Pointer max entries count
constexpr static auto PAGE_DIRECTORY_POINTR_SIZE {PAGE_MAP_LEVEL_4_SIZE};
// Page Directory max entries count
constexpr static auto PAGE_DIRECTORY_SIZE {PAGE_MAP_LEVEL_4_SIZE};
// Page Table max entries count
constexpr static auto PAGE_TABLE_SIZE {PAGE_MAP_LEVEL_4_SIZE};
// Page shift
constexpr static auto PAGE_SHIFT {12_usize};
// Page size
constexpr static auto PAGE_SIZE {1_usize << PAGE_SHIFT};
// Page mask
constexpr static auto PAGE_MASK {PAGE_SIZE - 1_usize};
#pragma push(pack, 1)
// Page
union alignas(4096_usize) page_t {
igros_pointer_t next; // Pointer to next page
igros_byte_t bytes[PAGE_SIZE]; // Page raw bytes
};
// Page table
union alignas(4096_usize) table_t {
igros_pointer_t next; // Pointer to next table
page_t* pages[PAGE_TABLE_SIZE]; // Page table entries
};
// Page directory
union alignas(4096_usize) directory_t {
igros_pointer_t next; // Pointer to next directory
table_t* tables[PAGE_DIRECTORY_SIZE]; // Page directory entries
};
// Page directory pointer
union alignas(4096_usize) directory_pointer_t {
igros_pointer_t next; // Pointer to next directory pointer
directory_t* directories[PAGE_DIRECTORY_SIZE]; // Page directory entries
};
// Page Map Level 4
union alignas(4096_usize) pml4_t {
directory_pointer_t* pointers[PAGE_DIRECTORY_SIZE]; // Page Map Level 4 entries
};
#pragma pop(pack)
private:
static table_t* mFreePages; // Free pages list
// Copy c-tor
paging(const paging &other) = delete;
// Copy assignment
paging& operator=(const paging &other) = delete;
// Move c-tor
paging(paging &&other) = delete;
// Move assignment
paging& operator=(paging &&other) = delete;
public:
// Page flags
enum class FLAGS : igros_quad_t {
CLEAR = 0x0000000000000000_u64,
PRESENT = 0x0000000000000001_u64,
WRITABLE = 0x0000000000000002_u64,
USER_ACCESSIBLE = 0x0000000000000004_u64,
WRITE_THROUGH = 0x0000000000000008_u64,
NON_CACHED = 0x0000000000000010_u64,
ACCESSED = 0x0000000000000020_u64,
DIRTY = 0x0000000000000040_u64,
HUGE = 0x0000000000000080_u64,
GLOBAL = 0x0000000000000100_u64,
USER_DEFINED = 0x0000000000000E00_u64,
NON_EXECUTABLE = 0x8000000000000000_u64,
FLAGS_MASK = PAGE_MASK,
PHYS_ADDR_MASK = ~PAGE_MASK
};
// Default c-tor
paging() noexcept = default;
// Identity map kernel + map higher-half + self-map page directory
static void init() noexcept;
// Enable paging
static void enable() noexcept;
// Disable paging
static void disable() noexcept;
// Enable Physical Address Extension
static void enablePAE() noexcept;
// Disable Physical Address Extension
static void disablePAE() noexcept;
// Initialize paging heap
static void heap(const igros_pointer_t phys, const igros_usize_t size) noexcept;
// Allocate page
[[nodiscard]]
static auto allocate() noexcept -> igros_pointer_t;
// Deallocate page
static void deallocate(const igros_pointer_t page) noexcept;
// Make PML4
[[nodiscard]]
static auto makePML4() noexcept -> pml4_t*;
// Make page directory pointer
[[nodiscard]]
static auto makeDirectoryPointer() noexcept -> directory_pointer_t*;
// Make page directory
[[nodiscard]]
static auto makeDirectory() noexcept -> directory_t*;
// Make page table
[[nodiscard]]
static auto makeTable() noexcept -> table_t*;
// Check directory pointer flags
[[nodiscard]]
static auto checkFlags(const directory_pointer_t* dirPtr, const klib::kFlags<FLAGS> flags) noexcept -> bool;
// Check directory flags
[[nodiscard]]
static auto checkFlags(const directory_t* dir, const klib::kFlags<FLAGS> flags) noexcept -> bool;
// Check table flags
[[nodiscard]]
static auto checkFlags(const table_t* table, const klib::kFlags<FLAGS> flags) noexcept -> bool;
// Check page flags
[[nodiscard]]
static auto checkFlags(const page_t* page, const klib::kFlags<FLAGS> flags) noexcept -> bool;
// Map virtual page to physical page (whole pml4, explicit pml4)
static void mapPML4(pml4_t* const pml4, const page_t* phys, const igros_pointer_t virt, const klib::kFlags<FLAGS> flags) noexcept;
// Map virtual page to physical page (whole pml4)
static void mapPML4(const page_t* phys, const igros_pointer_t virt, const klib::kFlags<FLAGS> flags) noexcept;
// Map virtual page to physical page (single directory pointer, explicit pml4)
static void mapDirectoryPointer(pml4_t* const pml4, const page_t* phys, const igros_pointer_t virt, const klib::kFlags<FLAGS> flags) noexcept;
// Map virtual page to physical page (single directory pointer)
static void mapDirectoryPointer(const page_t* phys, const igros_pointer_t virt, const klib::kFlags<FLAGS> flags) noexcept;
// Map virtual page to physical page (single directory, explicit pml4)
static void mapDirectory(pml4_t* const pml4, const page_t* phys, const igros_pointer_t virt, const klib::kFlags<FLAGS> flags) noexcept;
// Map virtual page to physical page (single directory)
static void mapDirectory(const page_t* phys, const igros_pointer_t virt, const klib::kFlags<FLAGS> flags) noexcept;
// Map virtual page to physical page (single table, explicit pml4)
static void mapTable(pml4_t* const pml4, const page_t* phys, const igros_pointer_t virt, const klib::kFlags<FLAGS> flags) noexcept;
// Map virtual page to physical page (single table)
static void mapTable(const page_t* phys, const igros_pointer_t virt, const klib::kFlags<FLAGS> flags) noexcept;
// Map virtual page to physical page (single page, explicit page directory)
static void mapPage(pml4_t* const dir, const page_t* phys, const igros_pointer_t virt, const klib::kFlags<FLAGS> flags) noexcept;
// Map virtual page to physical page (single page)
static void mapPage(const page_t* phys, const igros_pointer_t virt, const klib::kFlags<FLAGS> flags) noexcept;
// Convert virtual address to physical address
[[nodiscard]]
static auto translate(const igros_pointer_t addr) noexcept -> igros_pointer_t;
// Page Fault Exception handler
[[noreturn]]
static void exHandler(const register_t* regs) noexcept;
// Set page directory
static void flush(const pml4_t* const dir) noexcept;
};
} // namespace igros::x86_64