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
|
#include <hilbert/kernel/utility.hpp>
#include <hilbert/kernel/paging.hpp>
//see also ../documentation/memory.txt
extern "C" {
uint64_t __kernel_p4_paddr;
}
namespace hilbert::kernel::paging {
static constexpr uint64_t kernel_vram_start = 0xffffffffc0000000;
static constexpr uint64_t kernel_vram_end = 0xffffffffffe00000;
static constexpr uint64_t kernel_vram_pages =
(kernel_vram_end - kernel_vram_start) / 4096;
static constexpr uint64_t syscall_stack_bottom = 0xfffffffffff01000;
static constexpr uint64_t syscall_stack_top = 0xfffffffffffff000;
static constexpr uint64_t interrupt_stack_bottom = 0xffffffffffe01000;
static constexpr uint64_t interrupt_stack_top = 0xffffffffffeff000;
static constexpr uint64_t pram_pages = 1 << 23;
static uint64_t pram_usage_bitmap[pram_pages / 64];
void mark_all_pram_used() {
utility::mark_bitmap_region_one(pram_usage_bitmap, 0, pram_pages);
}
void mark_pram_region_free(uint64_t start_addr, uint64_t end_addr) {
utility::mark_bitmap_region_zero(
pram_usage_bitmap, start_addr / 4096,
utility::min(end_addr / 4096, pram_pages));
}
[[gnu::aligned(4096)]] uint64_t kernel_p4[512];
[[gnu::aligned(4096)]] uint64_t kernel_p3[512];
[[gnu::aligned(4096)]] uint64_t kernel_p2[512];
[[gnu::aligned(4096)]] uint64_t kernel_p1s[512 * 512];
uint64_t kernel_p4e;
void init_kernel_page_tables(uint64_t kernel_offset) {
__kernel_p4_paddr = (uint64_t)kernel_p4 - kernel_offset;
for (int i = 0; i < 511; ++i)
kernel_p4[i] = 0;
kernel_p4e = encode_pte(
(uint64_t)kernel_p3 - kernel_offset, false, true, true);
kernel_p4[511] = kernel_p4e;
for (int i = 0; i < 511; ++i)
kernel_p3[i] = 0;
kernel_p3[511] = encode_pte(
(uint64_t)kernel_p2 - kernel_offset, false, true, true);
for (int i = 0; i < 512; ++i)
kernel_p2[i] = encode_pte(
(uint64_t)kernel_p1s + 4096 * i - kernel_offset, false, true, true);
for (int i = 0; i < 512 * 512; ++i)
kernel_p1s[i] = 0;
}
void map_kernel_page(
uint64_t paddr, uint64_t vaddr, bool write, bool execute) {
uint64_t i = (vaddr - kernel_vram_start) / 4096;
kernel_p1s[i] = encode_pte(paddr, false, write, execute);
}
void unmap_kernel_page(uint64_t vaddr) {
uint64_t i = (vaddr - kernel_vram_start) / 4096;
kernel_p1s[i] = 0;
asm volatile (
"mov %%cr3, %%rax\nmov %%rax, %%cr3" ::: "%rax"
);
}
uint64_t take_pram_page() {
for (uint64_t i = 0; i < pram_pages / 64; ++i)
if (~pram_usage_bitmap[i] != 0)
for (int j = 0; j < 64; ++j)
if (~pram_usage_bitmap[i] & (1ULL << j)) {
pram_usage_bitmap[i] |= (1ULL << j);
return 4096 * (i * 64 + j);
}
//TODO: handle error
return 0;
}
void free_pram_page(uint64_t paddr) {
uint64_t page_i = paddr / 4096;
pram_usage_bitmap[page_i / 64] &= ~(1ULL << (page_i % 64));
}
void map_kernel_stacks() {
for (uint64_t vaddr = syscall_stack_bottom;
vaddr < syscall_stack_top; vaddr += 4096)
map_kernel_page(take_pram_page(), vaddr, true, false);
for (uint64_t vaddr = interrupt_stack_bottom;
vaddr < interrupt_stack_top; vaddr += 4096)
map_kernel_page(take_pram_page(), vaddr, true, false);
}
uint64_t find_unmapped_vram_region(uint64_t page_count) {
uint64_t start = 0;
uint64_t len = 0;
for (uint64_t i = 0; i < kernel_vram_pages; ++i)
if (kernel_p1s[i] == 0) {
++len;
if (len == page_count)
return start * 4096 + kernel_vram_start;
}
else {
start = i + 1;
len = 0;
}
//TODO: handle error
return 0;
}
void *map_new_kernel_pages(uint64_t count) {
uint64_t vaddr = find_unmapped_vram_region(count);
for (uint64_t i = 0; i < count; ++i)
map_kernel_page(take_pram_page(), vaddr + i * 4096, true, false);
return (void *)vaddr;
}
void map_new_kernel_page(uint64_t &vaddr_out, uint64_t &paddr_out) {
vaddr_out = find_unmapped_vram_region(1);
paddr_out = take_pram_page();
map_kernel_page(paddr_out, vaddr_out, true, false);
}
uint64_t get_used_vram_page_count() {
uint64_t count = 0;
for (uint64_t i = 0; i < kernel_vram_pages; ++i)
if (kernel_p1s[i] != 0)
++count;
return count;
}
uint64_t get_free_pram_page_count() {
uint64_t used_count = 0;
for (uint64_t i = 0; i < pram_pages / 64; ++i)
for (uint64_t j = 0; j < 64; ++j)
used_count += (pram_usage_bitmap[i] >> j) & 1;
return pram_pages - used_count;
}
}
|