blob: f1fd125f999bc87c5091e8eb01ea2d2b814c5e66 [file] [log] [blame]
swissChili825d46b2021-02-21 10:14:16 -08001#include "paging.h"
swissChilie4f01992021-02-25 15:38:12 -08002#include "alloc.h"
swissChili825d46b2021-02-21 10:14:16 -08003#include "io.h"
4#include "kint.h"
5#include "log.h"
6#include "pic.h"
7
swissChilicfd3c3c2021-04-03 15:04:24 -07008#define NUM_FRAMES 0xffffffff / 0x1000 / 32
swissChili825d46b2021-02-21 10:14:16 -08009/* frames bitset, 0 = free, 1 = used */
swissChilicfd3c3c2021-04-03 15:04:24 -070010static uint frames[NUM_FRAMES];
swissChili825d46b2021-02-21 10:14:16 -080011
12static uint first_page_table[1024] __attribute__((aligned(4096)));
swissChilie9289ee2021-03-20 21:54:28 -070013uint kernel_page_directory[1024] __attribute__((aligned(4096)));
swissChili825d46b2021-02-21 10:14:16 -080014
swissChili1e8b7562021-12-22 21:22:57 -080015
swissChili825d46b2021-02-21 10:14:16 -080016/* frame utils */
17
18#define BITS 32
19
20static void set_frame(size_t frame_addr)
21{
22 uint frame = frame_addr / 0x1000; // page aligned
23 frames[frame / BITS] |= 1 << (frame % BITS);
24}
25
26static bool test_frame(size_t frame_addr)
27{
28 uint frame = frame_addr / 0x1000; // page aligned
29 return frames[frame / BITS] & 1 << (frame % BITS);
30}
31
32static void clear_frame(size_t frame_addr)
33{
34 uint frame = frame_addr / 0x1000; // page aligned
35 frames[frame / BITS] &= ~(1 << (frame % BITS));
36}
37
38static uint first_free_frame()
39{
swissChilicfd3c3c2021-04-03 15:04:24 -070040 for (int i = 0; i < NUM_FRAMES / BITS; i++)
swissChili825d46b2021-02-21 10:14:16 -080041 {
42 /*
43 * If there are any zeroes, ~ will yield a non-zero result,
44 * meaning that there are pages free. Otherwise, check next set
45 */
46 if (!~frames[i])
47 continue;
48
49 for (int j = 0; j < BITS; j++)
50 {
swissChilicfd3c3c2021-04-03 15:04:24 -070051 if ((frames[i] & (1 << j)) == 0)
swissChili825d46b2021-02-21 10:14:16 -080052 {
53 /* found unused frame */
swissChilicfd3c3c2021-04-03 15:04:24 -070054 uint frame = i * BITS + j;
swissChili9bd74de2021-06-15 20:30:48 -070055 kprintf(DEBUG "first_free_frame returning %d\n", frame);
swissChilicfd3c3c2021-04-03 15:04:24 -070056// kpanic("asdf");
57 return frame;
swissChili825d46b2021-02-21 10:14:16 -080058 }
59 }
60 }
61
62 /* did not find a free frame, panic */
63 kpanic("first_free_frame failed! no free frames");
64}
65
swissChilie4f01992021-02-25 15:38:12 -080066void alloc_frame(uint *page_table_entry, bool user, bool writable)
swissChili825d46b2021-02-21 10:14:16 -080067{
swissChilicfd3c3c2021-04-03 15:04:24 -070068 if (*page_table_entry & 1)
swissChili825d46b2021-02-21 10:14:16 -080069 return; /* frame already allocated */
70
71 uint frame = first_free_frame();
swissChili9bd74de2021-06-15 20:30:48 -070072 // kprintf(DEBUG "first_free_frame found %d\n", frame);
swissChili825d46b2021-02-21 10:14:16 -080073 set_frame(frame * 0x1000); /* mark as mapped */
swissChilie4f01992021-02-25 15:38:12 -080074 *page_table_entry = frame | 1 | writable << 1 | user << 2;
swissChili825d46b2021-02-21 10:14:16 -080075}
76
77void free_frame(uint page)
78{
79 clear_frame(page / 0x1000);
80}
81
swissChilidc25b2b2021-02-23 17:07:13 -080082void map_4mb(uint *dir, size_t virt_start, size_t phys_start, bool user,
83 bool rw)
swissChilie0a79bb2021-02-22 19:54:48 -080084{
85 uint page = virt_start / 0x1000;
86 uint table = virt_start >> 22;
87
88 for (uint i = 0; i < 1024 * 0x1000; i += 0x1000)
89 {
swissChilicfd3c3c2021-04-03 15:04:24 -070090 set_frame(i);
swissChilie0a79bb2021-02-22 19:54:48 -080091 }
92
swissChilidc25b2b2021-02-23 17:07:13 -080093 dir[table] = 0b10000011;
94}
95
96uint *get_or_create_table(uint *dir, uint table, bool user, bool rw)
97{
swissChili1e8b7562021-12-22 21:22:57 -080098 // If used AND NOT 4mb page (see figure 4-4, page 115 of Intel
99 // manual volume 3)
100 if (dir[table] & 1 && dir[table] ^ 1 << 7)
swissChilidc25b2b2021-02-23 17:07:13 -0800101 {
swissChili1e8b7562021-12-22 21:22:57 -0800102 return (uint *)(size_t)PHYS_TO_VIRT((dir[table] & ~0xfff));
swissChilidc25b2b2021-02-23 17:07:13 -0800103 }
104
swissChili1e8b7562021-12-22 21:22:57 -0800105 uint *page_table = malloc(sizeof(uint[1024]));
swissChili7be32742021-04-03 21:17:24 -0700106 dir[table] = VIRT_TO_PHYS(page_table) | 1 | rw << 1 | user << 2;
swissChilidc25b2b2021-02-23 17:07:13 -0800107 return page_table;
108}
109
swissChili1e8b7562021-12-22 21:22:57 -0800110void unmap_all_frames(uint page_table_p)
111{
112 uint *table = (uint *)PHYS_TO_VIRT(page_table_p);
113
114 for (int i = 0; i < 1024; i++)
115 {
116 if (table[i] & 1)
117 {
118 clear_frame(table[i] >> 12);
119 }
120 }
121}
122
123void destroy_page_table_if_exists(uint *dir, uint table)
124{
125 // If used AND NOT 4mb page
126 if (dir[table] & 1 && dir[table] ^ 1 << 7)
127 {
128 unmap_all_frames(dir[table] >> 12);
129 free((void *)PHYS_TO_VIRT(dir[table] >> 12));
130 }
131}
132
swissChilie9289ee2021-03-20 21:54:28 -0700133void unmap_page(uint *dir, void *virt)
134{
135 uint page = ((size_t)virt / 0x1000) % 1024;
136 uint *table = get_or_create_table(dir, (size_t)virt >> 22, false, false);
137
138 table[page] = 0;
139}
140
141void map_page_to(uint *dir, void *virt, void *frame_p, bool writable, bool user)
142{
143 uint page = ((size_t)virt / 0x1000) % 1024;
144 uint *table = get_or_create_table(dir, (size_t)virt >> 22, false, false);
145
146 table[page] = (((uint)frame_p) ^ 0xfff) | 1 | writable << 1 | user << 2;
147}
148
swissChilie4f01992021-02-25 15:38:12 -0800149void alloc_kernel_page(uint *virt)
150{
swissChilie9289ee2021-03-20 21:54:28 -0700151 alloc_page(kernel_page_directory, virt);
152}
153
154void alloc_page(uint *dir, uint *virt)
155{
swissChilie4f01992021-02-25 15:38:12 -0800156 // Page number % pages per table
157 uint page = ((size_t)virt / 0x1000) % 1024;
swissChilie9289ee2021-03-20 21:54:28 -0700158 uint *table = get_or_create_table(dir, (size_t)virt >> 22, false, false);
swissChili9bd74de2021-06-15 20:30:48 -0700159 kprintf(DEBUG "table = 0x%x (virt)\n", table);
160 kprintf(DEBUG "dir entry = 0x%x\n", dir[(size_t)virt >> 22]);
swissChilie4f01992021-02-25 15:38:12 -0800161
162 alloc_frame(&table[page], false, false);
swissChilicfd3c3c2021-04-03 15:04:24 -0700163
swissChili9bd74de2021-06-15 20:30:48 -0700164 kprintf(DEBUG "alloc_page table[page] = %d (0x%x)\n", table[page], table[page]);
swissChilicfd3c3c2021-04-03 15:04:24 -0700165 return;
swissChilie4f01992021-02-25 15:38:12 -0800166}
167
168void alloc_kernel_page_range(uint *from, uint *to)
169{
swissChilie9289ee2021-03-20 21:54:28 -0700170 uint f = (size_t)from / 0x1000, t = (size_t)to / 0x1000;
swissChilie4f01992021-02-25 15:38:12 -0800171
172 do
173 {
174 alloc_kernel_page((uint *)(size_t)t);
175 t += 0x1000; // next page
176 } while (f < t);
177}
178
swissChilidc25b2b2021-02-23 17:07:13 -0800179void map_page(uint *dir, size_t virt_start, bool user, bool rw)
180{
swissChilie4f01992021-02-25 15:38:12 -0800181 // Page number % pages per table
182 uint page = (virt_start / 0x1000) % 1024;
swissChilidc25b2b2021-02-23 17:07:13 -0800183 uint table = virt_start >> 22;
184 uint frame = first_free_frame();
185
186 // If 4mb map OR (maps to table AND table maps page)
187 if ((dir[table] & 1 && dir[table] & 1 << 7) ||
188 (dir[table] >> 12 && ((uint *)(size_t)dir[table])[page] & 1))
189 {
190 return;
191 }
192
193 set_frame(frame);
194 uint *t = get_or_create_table(dir, table, user, rw);
195 alloc_frame(t + page, user, rw);
swissChilie0a79bb2021-02-22 19:54:48 -0800196}
197
swissChili825d46b2021-02-21 10:14:16 -0800198/* paging stuff */
199
swissChili1e8b7562021-12-22 21:22:57 -0800200uint *new_page_directory_v()
201{
202 // Only call this AFTER allocator + paging are initialized!
203 uint *dir = malloc(1024 * 4);
204 map_4mb(kernel_page_directory, (size_t)KERNEL_VIRTUAL_BASE, 0, false,
205 false);
206
207 return dir;
208}
209
210void free_page_directory_v(uint *dir_v)
211{
212 for (int i = 0; i < 1024; i++)
213 {
214 destroy_page_table_if_exists(dir_v, i);
215 }
216
217 free(dir_v);
218}
219
swissChilie0a79bb2021-02-22 19:54:48 -0800220void init_paging()
swissChili825d46b2021-02-21 10:14:16 -0800221{
swissChilie4f01992021-02-25 15:38:12 -0800222 memset(kernel_page_directory, 0, 1024 * 4);
223 map_4mb(kernel_page_directory, (size_t)KERNEL_VIRTUAL_BASE, 0, false,
224 false);
swissChili825d46b2021-02-21 10:14:16 -0800225
swissChilie4f01992021-02-25 15:38:12 -0800226 load_page_directory((uint)kernel_page_directory - 0xC0000000);
swissChili1e8b7562021-12-22 21:22:57 -0800227
swissChili825d46b2021-02-21 10:14:16 -0800228 add_interrupt_handler(14, page_fault);
229}
230
231void page_fault(struct registers *regs)
232{
swissChili9bd74de2021-06-15 20:30:48 -0700233 kprintf(ERROR "Page fault! eip = %d\n", regs->eip);
swissChili825d46b2021-02-21 10:14:16 -0800234 kpanic("Page fault");
235}