blob: 50ee7385928a33ca8b5328d668aa634087c542af [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
15/* frame utils */
16
17#define BITS 32
18
19static void set_frame(size_t frame_addr)
20{
21 uint frame = frame_addr / 0x1000; // page aligned
22 frames[frame / BITS] |= 1 << (frame % BITS);
23}
24
25static bool test_frame(size_t frame_addr)
26{
27 uint frame = frame_addr / 0x1000; // page aligned
28 return frames[frame / BITS] & 1 << (frame % BITS);
29}
30
31static void clear_frame(size_t frame_addr)
32{
33 uint frame = frame_addr / 0x1000; // page aligned
34 frames[frame / BITS] &= ~(1 << (frame % BITS));
35}
36
37static uint first_free_frame()
38{
swissChilicfd3c3c2021-04-03 15:04:24 -070039 for (int i = 0; i < NUM_FRAMES / BITS; i++)
swissChili825d46b2021-02-21 10:14:16 -080040 {
41 /*
42 * If there are any zeroes, ~ will yield a non-zero result,
43 * meaning that there are pages free. Otherwise, check next set
44 */
45 if (!~frames[i])
46 continue;
47
48 for (int j = 0; j < BITS; j++)
49 {
swissChilicfd3c3c2021-04-03 15:04:24 -070050 if ((frames[i] & (1 << j)) == 0)
swissChili825d46b2021-02-21 10:14:16 -080051 {
52 /* found unused frame */
swissChilicfd3c3c2021-04-03 15:04:24 -070053 uint frame = i * BITS + j;
swissChili9bd74de2021-06-15 20:30:48 -070054 kprintf(DEBUG "first_free_frame returning %d\n", frame);
swissChilicfd3c3c2021-04-03 15:04:24 -070055// kpanic("asdf");
56 return frame;
swissChili825d46b2021-02-21 10:14:16 -080057 }
58 }
59 }
60
61 /* did not find a free frame, panic */
62 kpanic("first_free_frame failed! no free frames");
63}
64
swissChilie4f01992021-02-25 15:38:12 -080065void alloc_frame(uint *page_table_entry, bool user, bool writable)
swissChili825d46b2021-02-21 10:14:16 -080066{
swissChilicfd3c3c2021-04-03 15:04:24 -070067 if (*page_table_entry & 1)
swissChili825d46b2021-02-21 10:14:16 -080068 return; /* frame already allocated */
69
70 uint frame = first_free_frame();
swissChili9bd74de2021-06-15 20:30:48 -070071 // kprintf(DEBUG "first_free_frame found %d\n", frame);
swissChili825d46b2021-02-21 10:14:16 -080072 set_frame(frame * 0x1000); /* mark as mapped */
swissChilie4f01992021-02-25 15:38:12 -080073 *page_table_entry = frame | 1 | writable << 1 | user << 2;
swissChili825d46b2021-02-21 10:14:16 -080074}
75
76void free_frame(uint page)
77{
78 clear_frame(page / 0x1000);
79}
80
swissChilidc25b2b2021-02-23 17:07:13 -080081void map_4mb(uint *dir, size_t virt_start, size_t phys_start, bool user,
82 bool rw)
swissChilie0a79bb2021-02-22 19:54:48 -080083{
84 uint page = virt_start / 0x1000;
85 uint table = virt_start >> 22;
86
87 for (uint i = 0; i < 1024 * 0x1000; i += 0x1000)
88 {
swissChilicfd3c3c2021-04-03 15:04:24 -070089 set_frame(i);
swissChilie0a79bb2021-02-22 19:54:48 -080090 }
91
swissChilidc25b2b2021-02-23 17:07:13 -080092 dir[table] = 0b10000011;
93}
94
95uint *get_or_create_table(uint *dir, uint table, bool user, bool rw)
96{
97 if (dir[table] >> 12)
98 {
swissChilicfd3c3c2021-04-03 15:04:24 -070099 return (uint *)(size_t)PHYS_TO_VIRT((dir[table] ^ 0xfff));
swissChilidc25b2b2021-02-23 17:07:13 -0800100 }
101
102 uint *page_table = kmalloc_a(sizeof(uint[1024]));
swissChili7be32742021-04-03 21:17:24 -0700103 dir[table] = VIRT_TO_PHYS(page_table) | 1 | rw << 1 | user << 2;
swissChilidc25b2b2021-02-23 17:07:13 -0800104 return page_table;
105}
106
swissChilie9289ee2021-03-20 21:54:28 -0700107void unmap_page(uint *dir, void *virt)
108{
109 uint page = ((size_t)virt / 0x1000) % 1024;
110 uint *table = get_or_create_table(dir, (size_t)virt >> 22, false, false);
111
112 table[page] = 0;
113}
114
115void map_page_to(uint *dir, void *virt, void *frame_p, bool writable, bool user)
116{
117 uint page = ((size_t)virt / 0x1000) % 1024;
118 uint *table = get_or_create_table(dir, (size_t)virt >> 22, false, false);
119
120 table[page] = (((uint)frame_p) ^ 0xfff) | 1 | writable << 1 | user << 2;
121}
122
swissChilie4f01992021-02-25 15:38:12 -0800123void alloc_kernel_page(uint *virt)
124{
swissChilie9289ee2021-03-20 21:54:28 -0700125 alloc_page(kernel_page_directory, virt);
126}
127
128void alloc_page(uint *dir, uint *virt)
129{
swissChilie4f01992021-02-25 15:38:12 -0800130 // Page number % pages per table
131 uint page = ((size_t)virt / 0x1000) % 1024;
swissChilie9289ee2021-03-20 21:54:28 -0700132 uint *table = get_or_create_table(dir, (size_t)virt >> 22, false, false);
swissChili9bd74de2021-06-15 20:30:48 -0700133 kprintf(DEBUG "table = 0x%x (virt)\n", table);
134 kprintf(DEBUG "dir entry = 0x%x\n", dir[(size_t)virt >> 22]);
swissChilie4f01992021-02-25 15:38:12 -0800135
136 alloc_frame(&table[page], false, false);
swissChilicfd3c3c2021-04-03 15:04:24 -0700137
swissChili9bd74de2021-06-15 20:30:48 -0700138 kprintf(DEBUG "alloc_page table[page] = %d (0x%x)\n", table[page], table[page]);
swissChilicfd3c3c2021-04-03 15:04:24 -0700139 return;
swissChilie4f01992021-02-25 15:38:12 -0800140}
141
142void alloc_kernel_page_range(uint *from, uint *to)
143{
swissChilie9289ee2021-03-20 21:54:28 -0700144 uint f = (size_t)from / 0x1000, t = (size_t)to / 0x1000;
swissChilie4f01992021-02-25 15:38:12 -0800145
146 do
147 {
148 alloc_kernel_page((uint *)(size_t)t);
149 t += 0x1000; // next page
150 } while (f < t);
151}
152
swissChilidc25b2b2021-02-23 17:07:13 -0800153void map_page(uint *dir, size_t virt_start, bool user, bool rw)
154{
swissChilie4f01992021-02-25 15:38:12 -0800155 // Page number % pages per table
156 uint page = (virt_start / 0x1000) % 1024;
swissChilidc25b2b2021-02-23 17:07:13 -0800157 uint table = virt_start >> 22;
158 uint frame = first_free_frame();
159
160 // If 4mb map OR (maps to table AND table maps page)
161 if ((dir[table] & 1 && dir[table] & 1 << 7) ||
162 (dir[table] >> 12 && ((uint *)(size_t)dir[table])[page] & 1))
163 {
164 return;
165 }
166
167 set_frame(frame);
168 uint *t = get_or_create_table(dir, table, user, rw);
169 alloc_frame(t + page, user, rw);
swissChilie0a79bb2021-02-22 19:54:48 -0800170}
171
swissChili825d46b2021-02-21 10:14:16 -0800172/* paging stuff */
173
swissChilie0a79bb2021-02-22 19:54:48 -0800174void init_paging()
swissChili825d46b2021-02-21 10:14:16 -0800175{
swissChilie4f01992021-02-25 15:38:12 -0800176 memset(kernel_page_directory, 0, 1024 * 4);
177 map_4mb(kernel_page_directory, (size_t)KERNEL_VIRTUAL_BASE, 0, false,
178 false);
swissChili825d46b2021-02-21 10:14:16 -0800179
swissChilie4f01992021-02-25 15:38:12 -0800180 load_page_directory((uint)kernel_page_directory - 0xC0000000);
swissChili825d46b2021-02-21 10:14:16 -0800181 add_interrupt_handler(14, page_fault);
182}
183
184void page_fault(struct registers *regs)
185{
swissChili9bd74de2021-06-15 20:30:48 -0700186 kprintf(ERROR "Page fault! eip = %d\n", regs->eip);
swissChili825d46b2021-02-21 10:14:16 -0800187 kpanic("Page fault");
188}