blob: 62636b3da720ed8f0eea5029b6f502e69538b19a [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
swissChili825d46b2021-02-21 10:14:16 -08008/* frames bitset, 0 = free, 1 = used */
swissChilie4f01992021-02-25 15:38:12 -08009static uint frames[0xffffffff / 0x1000 / 32];
swissChili825d46b2021-02-21 10:14:16 -080010static ulong num_frames;
11
12static uint first_page_table[1024] __attribute__((aligned(4096)));
swissChilie4f01992021-02-25 15:38:12 -080013static uint 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{
39 for (int i = 0; i < num_frames / BITS; i++)
40 {
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 {
50 if ((frames[i] & 1 << j) == 0)
51 {
52 /* found unused frame */
53 return i * BITS + j;
54 }
55 }
56 }
57
58 /* did not find a free frame, panic */
59 kpanic("first_free_frame failed! no free frames");
60}
61
swissChilie4f01992021-02-25 15:38:12 -080062void alloc_frame(uint *page_table_entry, bool user, bool writable)
swissChili825d46b2021-02-21 10:14:16 -080063{
swissChilie4f01992021-02-25 15:38:12 -080064 if (*page_table_entry >> 12)
swissChili825d46b2021-02-21 10:14:16 -080065 return; /* frame already allocated */
66
67 uint frame = first_free_frame();
68 // kprintf("first_free_frame found %d\n", frame);
69 set_frame(frame * 0x1000); /* mark as mapped */
swissChilie4f01992021-02-25 15:38:12 -080070 *page_table_entry = frame | 1 | writable << 1 | user << 2;
swissChili825d46b2021-02-21 10:14:16 -080071}
72
73void free_frame(uint page)
74{
75 clear_frame(page / 0x1000);
76}
77
swissChilidc25b2b2021-02-23 17:07:13 -080078void map_4mb(uint *dir, size_t virt_start, size_t phys_start, bool user,
79 bool rw)
swissChilie0a79bb2021-02-22 19:54:48 -080080{
81 uint page = virt_start / 0x1000;
82 uint table = virt_start >> 22;
83
84 for (uint i = 0; i < 1024 * 0x1000; i += 0x1000)
85 {
86 set_frame(page + i);
87 }
88
swissChilidc25b2b2021-02-23 17:07:13 -080089 dir[table] = 0b10000011;
90}
91
92uint *get_or_create_table(uint *dir, uint table, bool user, bool rw)
93{
94 if (dir[table] >> 12)
95 {
96 return (uint *)(size_t)(dir[table] ^ 0xfff);
97 }
98
99 uint *page_table = kmalloc_a(sizeof(uint[1024]));
100 dir[table] = (uint)page_table | 1 | rw << 1 | user << 2;
101 return page_table;
102}
103
swissChilie4f01992021-02-25 15:38:12 -0800104void alloc_kernel_page(uint *virt)
105{
106 // Page number % pages per table
107 uint page = ((size_t)virt / 0x1000) % 1024;
108 uint *table = get_or_create_table(kernel_page_directory, (size_t)virt >> 22,
109 false, false);
110
111 alloc_frame(&table[page], false, false);
112}
113
114void alloc_kernel_page_range(uint *from, uint *to)
115{
116 uint f = (size_t)from / 0x1000,
117 t = (size_t)to / 0x1000;
118
119 do
120 {
121 alloc_kernel_page((uint *)(size_t)t);
122 t += 0x1000; // next page
123 } while (f < t);
124}
125
swissChilidc25b2b2021-02-23 17:07:13 -0800126void map_page(uint *dir, size_t virt_start, bool user, bool rw)
127{
swissChilie4f01992021-02-25 15:38:12 -0800128 // Page number % pages per table
129 uint page = (virt_start / 0x1000) % 1024;
swissChilidc25b2b2021-02-23 17:07:13 -0800130 uint table = virt_start >> 22;
131 uint frame = first_free_frame();
132
133 // If 4mb map OR (maps to table AND table maps page)
134 if ((dir[table] & 1 && dir[table] & 1 << 7) ||
135 (dir[table] >> 12 && ((uint *)(size_t)dir[table])[page] & 1))
136 {
137 return;
138 }
139
140 set_frame(frame);
141 uint *t = get_or_create_table(dir, table, user, rw);
142 alloc_frame(t + page, user, rw);
swissChilie0a79bb2021-02-22 19:54:48 -0800143}
144
swissChili825d46b2021-02-21 10:14:16 -0800145/* paging stuff */
146
swissChilie0a79bb2021-02-22 19:54:48 -0800147void init_paging()
swissChili825d46b2021-02-21 10:14:16 -0800148{
swissChilie4f01992021-02-25 15:38:12 -0800149 memset(kernel_page_directory, 0, 1024 * 4);
150 map_4mb(kernel_page_directory, (size_t)KERNEL_VIRTUAL_BASE, 0, false,
151 false);
swissChili825d46b2021-02-21 10:14:16 -0800152
swissChilie4f01992021-02-25 15:38:12 -0800153 load_page_directory((uint)kernel_page_directory - 0xC0000000);
swissChili825d46b2021-02-21 10:14:16 -0800154 add_interrupt_handler(14, page_fault);
155}
156
157void page_fault(struct registers *regs)
158{
159 kprintf("Page fault! eip = %d\n", regs->eip);
160 kpanic("Page fault");
161}