blob: ff6226bd57207c18105c0708b341939c5cad51f2 [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
swissChilib58ab672022-01-17 21:18:01 -08008/**
9 * NOTE: In order to understand this code you should have the paging
10 * section of the Intel IA-32 and 64 manual volume 3 open. Sadly I
11 * have littered this with magic numbers that you will need to consult
12 * the manual to understand.
13 * TODO: Fix this!
14 */
15
swissChilicfd3c3c2021-04-03 15:04:24 -070016#define NUM_FRAMES 0xffffffff / 0x1000 / 32
swissChili825d46b2021-02-21 10:14:16 -080017/* frames bitset, 0 = free, 1 = used */
swissChilicfd3c3c2021-04-03 15:04:24 -070018static uint frames[NUM_FRAMES];
swissChili825d46b2021-02-21 10:14:16 -080019
swissChilie9289ee2021-03-20 21:54:28 -070020uint kernel_page_directory[1024] __attribute__((aligned(4096)));
swissChili825d46b2021-02-21 10:14:16 -080021
swissChili1e8b7562021-12-22 21:22:57 -080022
swissChili825d46b2021-02-21 10:14:16 -080023/* frame utils */
24
25#define BITS 32
26
27static void set_frame(size_t frame_addr)
28{
29 uint frame = frame_addr / 0x1000; // page aligned
30 frames[frame / BITS] |= 1 << (frame % BITS);
31}
32
swissChili825d46b2021-02-21 10:14:16 -080033static void clear_frame(size_t frame_addr)
34{
35 uint frame = frame_addr / 0x1000; // page aligned
36 frames[frame / BITS] &= ~(1 << (frame % BITS));
37}
38
39static uint first_free_frame()
40{
swissChilicfd3c3c2021-04-03 15:04:24 -070041 for (int i = 0; i < NUM_FRAMES / BITS; i++)
swissChili825d46b2021-02-21 10:14:16 -080042 {
43 /*
44 * If there are any zeroes, ~ will yield a non-zero result,
45 * meaning that there are pages free. Otherwise, check next set
46 */
47 if (!~frames[i])
48 continue;
49
50 for (int j = 0; j < BITS; j++)
51 {
swissChilicfd3c3c2021-04-03 15:04:24 -070052 if ((frames[i] & (1 << j)) == 0)
swissChili825d46b2021-02-21 10:14:16 -080053 {
54 /* found unused frame */
swissChilicfd3c3c2021-04-03 15:04:24 -070055 uint frame = i * BITS + j;
swissChili9bd74de2021-06-15 20:30:48 -070056 kprintf(DEBUG "first_free_frame returning %d\n", frame);
swissChili14d0b842023-01-01 02:22:44 -050057
swissChilicfd3c3c2021-04-03 15:04:24 -070058 return frame;
swissChili825d46b2021-02-21 10:14:16 -080059 }
60 }
61 }
62
63 /* did not find a free frame, panic */
64 kpanic("first_free_frame failed! no free frames");
65}
66
swissChilie4f01992021-02-25 15:38:12 -080067void alloc_frame(uint *page_table_entry, bool user, bool writable)
swissChili825d46b2021-02-21 10:14:16 -080068{
swissChilicfd3c3c2021-04-03 15:04:24 -070069 if (*page_table_entry & 1)
swissChili825d46b2021-02-21 10:14:16 -080070 return; /* frame already allocated */
71
72 uint frame = first_free_frame();
swissChili9bd74de2021-06-15 20:30:48 -070073 // kprintf(DEBUG "first_free_frame found %d\n", frame);
swissChili825d46b2021-02-21 10:14:16 -080074 set_frame(frame * 0x1000); /* mark as mapped */
swissChilie4f01992021-02-25 15:38:12 -080075 *page_table_entry = frame | 1 | writable << 1 | user << 2;
swissChili825d46b2021-02-21 10:14:16 -080076}
77
78void free_frame(uint page)
79{
80 clear_frame(page / 0x1000);
81}
82
swissChilidc25b2b2021-02-23 17:07:13 -080083void map_4mb(uint *dir, size_t virt_start, size_t phys_start, bool user,
84 bool rw)
swissChilie0a79bb2021-02-22 19:54:48 -080085{
swissChilie0a79bb2021-02-22 19:54:48 -080086 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{
swissChili14d0b842023-01-01 02:22:44 -050098 // If used AND NOT 4mb page (see figure 4-4, page 114 of Intel
swissChili1e8b7562021-12-22 21:22:57 -080099 // manual volume 3)
swissChili14d0b842023-01-01 02:22:44 -0500100 // bit 0 = used; bit 7 = 4MB?
101 if (dir[table] & 1 && dir[table] ^ (1 << 7))
swissChilidc25b2b2021-02-23 17:07:13 -0800102 {
swissChili14d0b842023-01-01 02:22:44 -0500103 // 12 LSBs are metadata
swissChili1e8b7562021-12-22 21:22:57 -0800104 return (uint *)(size_t)PHYS_TO_VIRT((dir[table] & ~0xfff));
swissChilidc25b2b2021-02-23 17:07:13 -0800105 }
106
swissChili1e8b7562021-12-22 21:22:57 -0800107 uint *page_table = malloc(sizeof(uint[1024]));
swissChili7be32742021-04-03 21:17:24 -0700108 dir[table] = VIRT_TO_PHYS(page_table) | 1 | rw << 1 | user << 2;
swissChilidc25b2b2021-02-23 17:07:13 -0800109 return page_table;
110}
111
swissChili1e8b7562021-12-22 21:22:57 -0800112void unmap_all_frames(uint page_table_p)
113{
114 uint *table = (uint *)PHYS_TO_VIRT(page_table_p);
115
116 for (int i = 0; i < 1024; i++)
117 {
118 if (table[i] & 1)
119 {
120 clear_frame(table[i] >> 12);
121 }
122 }
123}
124
125void destroy_page_table_if_exists(uint *dir, uint table)
126{
127 // If used AND NOT 4mb page
128 if (dir[table] & 1 && dir[table] ^ 1 << 7)
129 {
130 unmap_all_frames(dir[table] >> 12);
131 free((void *)PHYS_TO_VIRT(dir[table] >> 12));
132 }
133}
134
swissChilie9289ee2021-03-20 21:54:28 -0700135void unmap_page(uint *dir, void *virt)
136{
137 uint page = ((size_t)virt / 0x1000) % 1024;
138 uint *table = get_or_create_table(dir, (size_t)virt >> 22, false, false);
139
140 table[page] = 0;
141}
142
swissChili14d0b842023-01-01 02:22:44 -0500143// TODO: This entire function seems wrong.
swissChilie9289ee2021-03-20 21:54:28 -0700144void map_page_to(uint *dir, void *virt, void *frame_p, bool writable, bool user)
145{
146 uint page = ((size_t)virt / 0x1000) % 1024;
147 uint *table = get_or_create_table(dir, (size_t)virt >> 22, false, false);
148
swissChili14d0b842023-01-01 02:22:44 -0500149 // TODO: is the xor here correct?
swissChilie9289ee2021-03-20 21:54:28 -0700150 table[page] = (((uint)frame_p) ^ 0xfff) | 1 | writable << 1 | user << 2;
151}
152
swissChilie4f01992021-02-25 15:38:12 -0800153void alloc_kernel_page(uint *virt)
154{
swissChilie9289ee2021-03-20 21:54:28 -0700155 alloc_page(kernel_page_directory, virt);
156}
157
158void alloc_page(uint *dir, uint *virt)
159{
swissChilie4f01992021-02-25 15:38:12 -0800160 // Page number % pages per table
161 uint page = ((size_t)virt / 0x1000) % 1024;
swissChilie9289ee2021-03-20 21:54:28 -0700162 uint *table = get_or_create_table(dir, (size_t)virt >> 22, false, false);
swissChili14d0b842023-01-01 02:22:44 -0500163 // kprintf(DEBUG "table = 0x%x (virt)\n", table);
164 // kprintf(DEBUG "dir entry = 0x%x\n", dir[(size_t)virt >> 22]);
swissChilie4f01992021-02-25 15:38:12 -0800165
166 alloc_frame(&table[page], false, false);
swissChilicfd3c3c2021-04-03 15:04:24 -0700167
swissChili14d0b842023-01-01 02:22:44 -0500168 // kprintf(DEBUG "alloc_page table[page] = %d (0x%x)\n", table[page], table[page]);
swissChilicfd3c3c2021-04-03 15:04:24 -0700169 return;
swissChilie4f01992021-02-25 15:38:12 -0800170}
171
172void alloc_kernel_page_range(uint *from, uint *to)
173{
swissChilie9289ee2021-03-20 21:54:28 -0700174 uint f = (size_t)from / 0x1000, t = (size_t)to / 0x1000;
swissChilie4f01992021-02-25 15:38:12 -0800175
176 do
177 {
178 alloc_kernel_page((uint *)(size_t)t);
179 t += 0x1000; // next page
180 } while (f < t);
181}
182
swissChilidc25b2b2021-02-23 17:07:13 -0800183void map_page(uint *dir, size_t virt_start, bool user, bool rw)
184{
swissChilie4f01992021-02-25 15:38:12 -0800185 // Page number % pages per table
186 uint page = (virt_start / 0x1000) % 1024;
swissChilidc25b2b2021-02-23 17:07:13 -0800187 uint table = virt_start >> 22;
188 uint frame = first_free_frame();
189
190 // If 4mb map OR (maps to table AND table maps page)
191 if ((dir[table] & 1 && dir[table] & 1 << 7) ||
192 (dir[table] >> 12 && ((uint *)(size_t)dir[table])[page] & 1))
193 {
194 return;
195 }
196
197 set_frame(frame);
198 uint *t = get_or_create_table(dir, table, user, rw);
199 alloc_frame(t + page, user, rw);
swissChilie0a79bb2021-02-22 19:54:48 -0800200}
201
swissChili825d46b2021-02-21 10:14:16 -0800202/* paging stuff */
203
swissChili1e8b7562021-12-22 21:22:57 -0800204uint *new_page_directory_v()
205{
206 // Only call this AFTER allocator + paging are initialized!
207 uint *dir = malloc(1024 * 4);
208 map_4mb(kernel_page_directory, (size_t)KERNEL_VIRTUAL_BASE, 0, false,
209 false);
210
211 return dir;
212}
213
214void free_page_directory_v(uint *dir_v)
215{
216 for (int i = 0; i < 1024; i++)
217 {
218 destroy_page_table_if_exists(dir_v, i);
219 }
220
221 free(dir_v);
222}
223
swissChilie0a79bb2021-02-22 19:54:48 -0800224void init_paging()
swissChili825d46b2021-02-21 10:14:16 -0800225{
swissChilie4f01992021-02-25 15:38:12 -0800226 memset(kernel_page_directory, 0, 1024 * 4);
227 map_4mb(kernel_page_directory, (size_t)KERNEL_VIRTUAL_BASE, 0, false,
228 false);
swissChili825d46b2021-02-21 10:14:16 -0800229
swissChili14d0b842023-01-01 02:22:44 -0500230 load_page_directory(VIRT_TO_PHYS(kernel_page_directory));
swissChili825d46b2021-02-21 10:14:16 -0800231}
232
swissChilie4229a22023-01-01 15:59:53 -0500233#ifdef TEST_PAGING
swissChili14d0b842023-01-01 02:22:44 -0500234void test_paging()
swissChili825d46b2021-02-21 10:14:16 -0800235{
swissChili14d0b842023-01-01 02:22:44 -0500236 // a random page base address
237 uint *base = (uint *)0xFFFFFE000;
238
239 kprintf(INFO "Allocating page (expect frame 1024)\n");
240 alloc_page(kernel_page_directory, base);
241
242 kprintf(INFO "Writing 10 words to page\n");
243 for (int i = 0; i < 10; i++)
244 {
245 base[i] = i;
246 }
swissChili825d46b2021-02-21 10:14:16 -0800247}
swissChilie4229a22023-01-01 15:59:53 -0500248#endif