3#include "../../lib/base/generic.h"
4#include "../../lib/base/stdio.h"
5#include "../../lib/base/memory.h"
6#include "../../lib/base/heap.h"
8#include "../drivers/screen.h"
13#define paging_pool_start 0x100000
14#define paging_pool_end 0xf00000
16#define user_space_start 0x1000000
17#define user_space_end 0x10000000
20extern void* stack_pointer;
21extern u_dword stack_size;
23extern void copy_page_physical(u_dword source, u_dword destination);
27void* page_dirs, * page_tables;
28byte* paging_pool, * user_space_pool;
32 return (
void*) (page.frame * page_size);
40static u_dword get_free_bit(u_byte search) {
41 if (search == full_byte)
return search;
42 for (u_dword i = 0; i < 8; ++i)
if (!(search & (1u << i)))
return i;
45static void* allocate_frame() {
46 for (u_dword i = 0; i <
size_of(user_space_pool); ++i) {
47 u_dword free_bit = get_free_bit(user_space_pool[i]);
48 if (free_bit != full_byte) {
49 user_space_pool[i] |= (1u << free_bit);
50 return (
void *) (user_space_start + (i * 8 + free_bit) * page_size);
57 for (u_dword i = 0; i <
size_of(paging_pool); ++i) {
58 u_dword free_bit = get_free_bit(paging_pool[i]);
59 if (free_bit != full_byte) {
60 paging_pool[i] |= (1u << free_bit);
61 void* address = (
void *) (paging_pool_start + (i * 8 + free_bit) * page_size);
62 memory_clear((
byte*) address, page_size, 0);
69static void free_frame(
void* address) {
70 u_dword index = (u_dword) address - user_space_start;
71 user_space_pool[index / 8] &= ~(0x1 << (index % 8));
74static void free_page_table(
page_folder* table,
boolean top_level) {
75 u_dword index = (u_dword) table - paging_pool_start;
76 paging_pool[index / 8] &= ~(0x1 << (index % 8));
77 for (u_dword i = 0; i < pages_in_table; i++) {
78 void* contents = get_contents_as_page(table->contents[i]);
79 if (top_level) free_page_table((
page_folder*) contents,
false);
80 else free_frame(contents);
85static page_pointer create_page_entry(
const void* address,
boolean is_kernel,
boolean is_writeable) {
87 page_table.frame = (u_dword) address / page_size;
88 page_table.user = is_kernel ? 0 : 1;
89 page_table.rw = is_writeable ? 1 : 0;
90 page_table.present = 1;
95 if (address > user_space_end)
return nullptr;
99 u_dword table_idx = address / pages_in_table;
101 u_dword entry = (u_dword) get_contents_as_page(dir->contents[table_idx]);
103 if (!make)
return nullptr;
104 else dir->contents[table_idx] = create_page_entry((
void*) allocate_page_folder(),
true,
true);
106 return &get_contents_as_table(dir->contents[table_idx])[address % pages_in_table];
112 copy.present = page.present;
114 copy.user = page.user;
115 copy.write = page.write;
116 copy.cache = page.cache;
117 copy.accessed = page.accessed;
118 copy.dirty = page.dirty;
119 copy.zero = page.zero;
120 copy.global = page.global;
121 copy.unused = page.unused;
122 copy.frame = page.frame;
126static boolean contains_user_pages(
page_pointer folder) {
127 page_pointer* directory = get_contents_as_table(folder);
128 boolean contains =
false;
129 for (u_dword i = 0; i < pages_in_table; i++) contains |= directory[i].user;
139 for (
int i = 0; i < pages_in_table; i++) {
140 if (pages[i].present == 0)
continue;
141 if (src.user || pages[i].user) {
143 table->contents[i] = clone_page_pointer(pages[i]);
145 table->contents[i].frame = (u_dword) allocate_frame() / page_size;
147 copy_page_physical(pages[i].frame * page_size, table->contents[i].frame * page_size);
148 }
else table->contents[i] = pages[i];
152 table_pointer.frame = (u_dword) table / page_size;
153 return table_pointer;
161 for (
int i = 0; i < pages_in_table; i++) {
162 if (src->contents[i].present == 0)
continue;
163 else if (src->contents[i].user || contains_user_pages(src->contents[i])) {
165 dir->contents[i] = clone_table(src->contents[i]);
168 dir->contents[i] = src->contents[i];
178 u_dword faulting_address;
179 asm (
"mov %%cr2, %0" :
"=r" (faulting_address));
182 boolean present = regs->err_code & 0x1;
183 boolean rw = regs->err_code & 0x2;
184 boolean us = regs->err_code & 0x4;
185 boolean reserved = regs->err_code & 0x8;
186 boolean id = regs->err_code & 0x10;
189 PANIC(
"Page fault! (p: %d, w: %d, u: %d, r: %d) at %h (EIP: %h)", present, rw, us, reserved, faulting_address, regs->eip)
193void initialise_paging() {
196 u_dword paging_pool_size = (paging_pool_end - paging_pool_start) / page_size / 8;
197 paging_pool =
ralloc(paging_pool_size);
198 memory_clear((
byte*) paging_pool, paging_pool_size, 0);
200 u_dword user_space_pool_size = (user_space_end - user_space_start) / page_size / 8;
201 user_space_pool =
ralloc(user_space_pool_size);
202 memory_clear((
byte*) user_space_pool, user_space_pool_size, 0);
205 kernel_directory = (
page_folder*) allocate_page_folder();
207 for (u_dword i = 0; i < user_space_start; i += page_size) {
208 boolean in_stack = i >= (u_dword) stack_pointer - stack_size && i < (u_dword) stack_pointer;
209 *get_page(i,
true, kernel_directory) = create_page_entry((
const byte*) i, !in_stack, in_stack);
213 set_interrupt_handler(14, page_fault);
216 current_directory = kernel_directory;
219 "mov %%cr0, %%eax;\n"
220 "or $0x80000000, %%eax;\n"
221 "mov %%eax, %%cr0;\n"
222 ::
"r"(¤t_directory->contents)
#define size_of(structure)
void * ralloc(u_dword size)