blob: 9da17dc2ee8accd0176ab97ecbb5e8ea667eec14 [file] [log] [blame]
swissChili825d46b2021-02-21 10:14:16 -08001#include "paging.h"
2#include "io.h"
3#include "kint.h"
4#include "log.h"
5#include "pic.h"
6
7extern uint end;
8static size_t alloc_base = (size_t)&end;
9
10/* frames bitset, 0 = free, 1 = used */
11static uint *frames;
12static ulong num_frames;
13
14static uint first_page_table[1024] __attribute__((aligned(4096)));
swissChilie0a79bb2021-02-22 19:54:48 -080015static uint page_directory[1024] __attribute__((aligned(4096)));
swissChili825d46b2021-02-21 10:14:16 -080016
17void *_kmalloc(size_t size, bool align, void **phys)
18{
19 if (align && (alloc_base & 0xfff)) // if not yet aligned
20 {
21 alloc_base &= ~0xfff;
22 alloc_base += 0x1000;
23 }
24
25 if (phys)
26 {
27 *phys = (void *)alloc_base;
28 }
29
30 size_t addr = alloc_base;
31 alloc_base += size;
32 return (void *)addr;
33}
34
35void *kmalloc(size_t size)
36{
37 return _kmalloc(size, false, NULL);
38}
39
40void *kmalloc_a(size_t size)
41{
42 return _kmalloc(size, true, NULL);
43}
44
45void *kmalloc_ap(size_t size, void **p)
46{
47 return _kmalloc(size, true, p);
48}
49
50/* frame utils */
51
52#define BITS 32
53
54static void set_frame(size_t frame_addr)
55{
56 uint frame = frame_addr / 0x1000; // page aligned
57 frames[frame / BITS] |= 1 << (frame % BITS);
58}
59
60static bool test_frame(size_t frame_addr)
61{
62 uint frame = frame_addr / 0x1000; // page aligned
63 return frames[frame / BITS] & 1 << (frame % BITS);
64}
65
66static void clear_frame(size_t frame_addr)
67{
68 uint frame = frame_addr / 0x1000; // page aligned
69 frames[frame / BITS] &= ~(1 << (frame % BITS));
70}
71
72static uint first_free_frame()
73{
74 for (int i = 0; i < num_frames / BITS; i++)
75 {
76 /*
77 * If there are any zeroes, ~ will yield a non-zero result,
78 * meaning that there are pages free. Otherwise, check next set
79 */
80 if (!~frames[i])
81 continue;
82
83 for (int j = 0; j < BITS; j++)
84 {
85 if ((frames[i] & 1 << j) == 0)
86 {
87 /* found unused frame */
88 return i * BITS + j;
89 }
90 }
91 }
92
93 /* did not find a free frame, panic */
94 kpanic("first_free_frame failed! no free frames");
95}
96
swissChilidc25b2b2021-02-23 17:07:13 -080097void alloc_frame(uint *page, bool user, bool writable)
swissChili825d46b2021-02-21 10:14:16 -080098{
99 if (*page >> 12)
100 return; /* frame already allocated */
101
102 uint frame = first_free_frame();
103 // kprintf("first_free_frame found %d\n", frame);
104 set_frame(frame * 0x1000); /* mark as mapped */
swissChilidc25b2b2021-02-23 17:07:13 -0800105 *page = frame | 1 | writable << 1 | user << 2;
swissChili825d46b2021-02-21 10:14:16 -0800106}
107
108void free_frame(uint page)
109{
110 clear_frame(page / 0x1000);
111}
112
swissChilidc25b2b2021-02-23 17:07:13 -0800113void map_4mb(uint *dir, size_t virt_start, size_t phys_start, bool user,
114 bool rw)
swissChilie0a79bb2021-02-22 19:54:48 -0800115{
116 uint page = virt_start / 0x1000;
117 uint table = virt_start >> 22;
118
119 for (uint i = 0; i < 1024 * 0x1000; i += 0x1000)
120 {
121 set_frame(page + i);
122 }
123
swissChilidc25b2b2021-02-23 17:07:13 -0800124 dir[table] = 0b10000011;
125}
126
127uint *get_or_create_table(uint *dir, uint table, bool user, bool rw)
128{
129 if (dir[table] >> 12)
130 {
131 return (uint *)(size_t)(dir[table] ^ 0xfff);
132 }
133
134 uint *page_table = kmalloc_a(sizeof(uint[1024]));
135 dir[table] = (uint)page_table | 1 | rw << 1 | user << 2;
136 return page_table;
137}
138
139void map_page(uint *dir, size_t virt_start, bool user, bool rw)
140{
141 uint page = virt_start / 0x1000;
142 uint table = virt_start >> 22;
143 uint frame = first_free_frame();
144
145 // If 4mb map OR (maps to table AND table maps page)
146 if ((dir[table] & 1 && dir[table] & 1 << 7) ||
147 (dir[table] >> 12 && ((uint *)(size_t)dir[table])[page] & 1))
148 {
149 return;
150 }
151
152 set_frame(frame);
153 uint *t = get_or_create_table(dir, table, user, rw);
154 alloc_frame(t + page, user, rw);
swissChilie0a79bb2021-02-22 19:54:48 -0800155}
156
swissChili825d46b2021-02-21 10:14:16 -0800157/* paging stuff */
158
swissChilie0a79bb2021-02-22 19:54:48 -0800159void init_paging()
swissChili825d46b2021-02-21 10:14:16 -0800160{
swissChilidc25b2b2021-02-23 17:07:13 -0800161 frames = kmalloc_a(0x1000);
swissChilie0a79bb2021-02-22 19:54:48 -0800162 memset(page_directory, 0, 1024 * 4);
swissChilidc25b2b2021-02-23 17:07:13 -0800163 map_4mb(page_directory, (size_t)KERNEL_VIRTUAL_BASE, 0, false, false);
swissChili825d46b2021-02-21 10:14:16 -0800164
swissChilie0a79bb2021-02-22 19:54:48 -0800165 load_page_directory((uint)page_directory - 0xC0000000);
swissChili825d46b2021-02-21 10:14:16 -0800166 add_interrupt_handler(14, page_fault);
167}
168
169void page_fault(struct registers *regs)
170{
171 kprintf("Page fault! eip = %d\n", regs->eip);
172 kpanic("Page fault");
173}